javascript - Javascript - 使用ramdajs创建top 5聚合

我想转换这个输入


[


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


]



插入到输出


[


 { country: 'England', value: 800 },


 { country: 'Romania', value: 500 },


 { country: 'France', value: 200 },


 { country: 'Spain', value: 130 },


 { country: 'Other', value: 8 }


]



这基本上是对其他四个国家的价值求和。

i am using javascript with ramdajs , and i only managed do it in a somehow cumbersome way so far .

我正在寻找一个优雅的解决方案: 或者任何关于Ramda方法的想法?

时间:

(每个步骤都获得前一步骤的输出,一切都将在最后被放在一起。

步骤1:获取sums的map

你可以转换:


[


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


]



到这里:


{


 Albania: 4,


 England: 800,


 France: 200,


 Hungary: 3,


 Romania: 500,


 Spain: 130


}



用这个:


const reducer = reduceBy((sum, {value}) => sum + value, 0);


const reduceCountries = reducer(prop('country'));



步骤2:将它转换为排序数组


[


 { country: "Hungary", value: 3 },


 { country: "Albania", value: 4 },


 { country: "Spain", value: 130 },


 { country: "France", value: 200 },


 { country: "Romania", value: 500 },


 { country: "England", value: 800 }


]



可以使用以下方法执行这个操作:


const countryFromPair = ([country, value]) => ({country, value});


pipe(toPairs, map(countryFromPair), sortBy(prop('value')));



第3步:创建两个子组,非前4个国家和前4个国家,


[


 [


 { country: "Hungary", value: 3},


 { country: "Albania", value: 4}


 ],


 [


 { country: "Spain", value: 130 },


 { country: "France", value: 200 },


 { country: "Romania", value: 500 },


 { country: "England", value: 800 }


 ]


]



你可以通过以下方式执行这个操作:

 
splitAt(-4)



 

步骤4:合并第一个子组


[


 [


 { country: "Others", value: 7 }


 ],


 [


 { country: "Spain", value: 130 },


 { country: "France", value: 200 },


 { country: "Romania", value: 500 },


 { country: "England", value: 800 }


 ]


]



用这个:


over(lensIndex(0), compose(map(countryFromPair), toPairs, reduceOthers));



步骤5:展平整个数组


[


 { country: "Others", value: 7 },


 { country: "Spain", value: 130 },


 { country: "France", value: 200 },


 { country: "Romania", value: 500 },


 { country: "England", value: 800 }


]



 
flatten



 

完整的工作示例


const data = [


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


];



const reducer = reduceBy((sum, {value}) => sum + value, 0);


const reduceOthers = reducer(always('Others'));


const reduceCountries = reducer(prop('country'));


const countryFromPair = ([country, value]) => ({country, value});



const top5 = pipe(


 reduceCountries,


 toPairs,


 map(countryFromPair),


 sortBy(prop('value')),


 splitAt(-4),


 over(lensIndex(0), compose(map(countryFromPair), toPairs, reduceOthers)),


 flatten


);



top5(data)



使用更多Ramda函数,但是,不确定它是否更好:


let country = pipe(


 groupBy(prop('country')),


 map(pluck('value')),


 map(sum)


)([


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


]);



let splitCountry = pipe(


 map((k) => ({country: k, value: country[k]})),


 sortBy(prop('value')),


 reverse,


 splitAt(4)


)(keys(country));



splitCountry[0].push({country: 'Others', value: sum(map(prop('value'))(splitCountry[1]))});


splitCountry[0]



这是我的两分钱。


const a = [


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


];



const diff = (a, b) => b.value - a.value;


const addValues = (acc, {value}) => R.add(acc,value);


const count = R.reduce(addValues, 0);


const toCountry = ({country}) => country;


const toCountryObj = (x) => ({'country': x[0], 'value': x[1] });


const reduceC = R.reduceBy(addValues, [], toCountry);



const [countries, others] = R.compose(


 R.splitAt(4), 


 R.sort(diff), 


 R.chain(toCountryObj), 


 R.toPairs, 


 reduceC)(a);



const othersArray = [{ 'country': 'Others', 'value': count(others) }];



R.concat(countries, othersArray);



Ramda REPL

我尝试一下,尝试在大多数事情中使用它的功能。保持单独的pipe


const f = pipe(


 groupBy(prop('country')),


 map(map(prop('value'))),


 map(sum),


 toPairs(),


 sortBy(prop(1)),


 reverse(),


 addIndex(map)((val, idx) => idx<4?val:['Others',val[1]]),


 groupBy(prop(0)),


 map(map(prop(1))),


 map(sum),


 toPairs(),


 map(([a,b])=>({'country':a,'value':b}))


)



Ramda REPL

但是,我不认为它有任何可读性。

我可能会做这样的事情:


const aggregate = R.pipe(


 R.groupBy(R.prop('country')),


 R.toPairs,


 R.map(


 R.applySpec({ 


 country: R.head, 


 value: R.pipe(R.last, R.pluck('value'), R.sum),


 }),


 ),


 R.sort(R.descend(R.prop('value'))),


 R.splitAt(4),


 R.over(


 R.lensIndex(1), 


 R.applySpec({ 


 country: R.always('Others'), 


 value: R.pipe(R.pluck('value'), R.sum),


 }),


 ),


 R.unnest,


);



const data = [


 { country: 'France', value: 100 },


 { country: 'France', value: 100 },


 { country: 'Romania', value: 500 },


 { country: 'England', value: 400 },


 { country: 'England', value: 400 },


 { country: 'Spain', value: 130 },


 { country: 'Albania', value: 4 },


 { country: 'Hungary', value: 3 }


];



console.log('result', aggregate(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

我想你可以在缩小数组之前通过分割数组来稍微简化一下从Ramda来看可能如下所示:


const groupOthersKeeping = contriesToKeep => arr => [


 ...slice(0, contriesToKeep, arr),


 reduce(


 (acc, i) => ({ ...acc, value: acc.value + i.value }),


 { country: 'Others', value: 0 },


 slice(contriesToKeep, Infinity, arr)


 )


 ]



...