2016-04-01 19 views
2

JS using Ramda'da bir nesnenin listesini alan ve belirli özelliklerin toplamını döndüren bir işlevi uygulamaya çalışıyorum. Örneğin.İşlevsel Programlama: Özellikleri toplamı

R.map(R.props($1, _), $2) 

fonksiyonel programlamada böyle bir şey uygulamak için en zarif yolu nedir:

var l = [ 
    {a: 1, b: 2, c: 0}, 
    {a: 1, b: 3, c: -1}, 
    {a: 1, b: 4, c: 0}, 
] 
func(['a', 'b'], l) 
-> {a: 3, b: 9} 

Prensip olarak, böyle bir işlevi gerekir? R.map(R.props) açık nedenlerle çalışmıyor. Ben R.compose veya R.pipe bazı kombinasyonlar kullanmaya çalıştı ama

+1

'b' prop 9'a eşit olmaz mı? – axelduch

+0

Tamamen haklısınız! Üzgünüm, tamir ettim. – user3637203

cevap

2

Ben iki bölüme bu kıracak :

const fnOverProp = R.curry((fn, prop, list) => fn(R.pluck(prop, list))); 

const fnOverProps = R.curry((fn, props, list) => 
    R.fromPairs(R.zip(props)(R.map(fnOverProp(fn, __, list), props)))); 

(Üzgünüm, Creative blocum var) Burada isimlendirmek için k. Bu isimler oldukça korkunç)

Böyle kullanabiliriz. Ben senin fikrin genelleme ilk

fnOverProp(R.sum, 'b', list); //=> 9 
fnOverProps(R.sum, ['a', 'b'], list); //=> {a: 3, b: 9} 
const sumOverProps = fnOverProps(R.sum); 
sumOverProps(['a', 'c'], list); //=> {a: 3, c: -1} 

Not sum bir parametre yapmak. Bu, benim böyle bir işleve sahip olmak isteyebilecek tek şeyin bu olmadığını hissettirdi.

Daha sonra, tek bir özellik adıyla çalışan bir işleve ayrılıyorum. Bu bana kendi başına oldukça yararlı geliyor. Bunların bir listesi için bunu yapmanız gerekmeyebilir ve bu işlev kendi başına kullanmaya değerdir.

Bunu, ilk işlevi bir özellik listesi üzerinden eşleyen bir işlevde sardım.

(fn, props, list) => R.map(fnOverProp(fn, R.__, list), props) 

aradığınız nesne çıkışı içine sonuçların düz listesini dönüştürmek için iki sarmalayıcıları içine sarılmış: Bu gerçekten oldukça basit bir fonksiyon olduğunu unutmayın. R.zip(props)(<thatFn>, props), [['a', 3], ['c', -1]] içine [3, -1] döner ve R.fromPairs, {a: 3, c: -1} içine döndürür.

Bu, istediğinizi belirttiğiniz tek satır uygulamanızı size vermez. Açıkçası, birinci fonksiyonun tanımını ikinciye katlayabilirsiniz, ama bu size çok şey kazandırdığını düşünmüyorum. Ve nokta-ücretsiz yapılabilir olsa bile, bu durumda okunabilirliği azaltmak sadece beklerdi.

Bunu, aşağıdaki eylemde görebilirsiniz: Ramda REPL.

0

Bunu denemek olabilir şansı olmadığını:

function add(a, b){ 
    return Object.keys(a).reduce(function(p, c){ 
    p[c] += a[c]; 
    return p; 
    }, b); 
} 

console.log(R.reduce(add, {a:0, b:0, c:0}, l)) 

Bu da başka bir yaklaşımdır:

R.pipe(R.map(R.props(['a', 'b', 'c'])), R.transpose, R.map(R.sum))(l); 
+0

Bu kesinlikle doğru bir çözüm, ancak çok zarif değil. İdeal olarak, hesaplamak istediğimi ifade eden tek bir satır arıyorum. Ayrıca, çözümü benzer bağlamlarda ortaya çıkabilecek diğer sorunlara da uygulamak istiyorum. – user3637203

+0

İkinci yaklaşım, tek satırda ifade edilir, umarım bu yardımcı olabilir. –

+0

Teşekkürler, ben daha çok R.pipe (R.map (R.props), R. Transferi, R.map (R.sum)) gibi bir şey arıyorum (['a', 'b', 'c') ], l). Bu iş gibi bir şey yapmanın hilesi, aslında anlamadığım işlevsel programlamadaki kavramdır. – user3637203

1

Bu, aynı zamanda nesne listesinin üzerinde bir redüktör olarak da tanımlanabilir.

reduce(useWith(mergeWith(add, [identity, pick(props)])) 

Ardından olmadığı konusunda iki seçenek vardır: sonucun bazı ilk devlet göz önüne alındığında, props biz ilgilenen özelliklerin listesidir iki nesnenin özelliklerini, sonuçlarını özetleyebilirim bir işlev istiyorum liste potansiyel olarak boş değildir veya en küçük bir nesneye sahip olması garantidir. Listenin boş olmaması garantiliyse, redüktörün başlangıç ​​değeri sadece listenin başı olabilir ve listenin üst üste gelmesi için kuyruk görevi görür. Liste potansiyel boş olabilir, ancak reduce fonksiyon boş değerleri (bu durumda sıfır) ile başlatılması gerekir ise

const func = (props, objs) => 
    reduce(useWith(mergeWith(add), [identity, pick(props)]), pick(props, head(objs)), tail(objs)) 

.

const func = (props, objs) => 
    reduce(useWith(mergeWith(add), [identity, pick(props)]), pick(props, map(flip(objOf)(0), props)), objs)