Javascript 使用ramdajs创建前5名聚合

Javascript 使用ramdajs创建前5名聚合,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,我想转换这个输入 [ { country: 'France', value: 100 }, { country: 'France', value: 100 }, { country: 'Romania', value: 500 }, { country: 'England', value: 400 }, { country: 'England', value: 400 }, { country: 'S

我想转换这个输入

[
        { 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 }
]
这基本上是对前4+个其他国家的值求和

我正在使用javascript,并且我只在一个特定的时间内完成了它


我正在寻找一个优雅的解决方案:有没有功能性程序员能够提供他们的解决方案?或者有什么ramda方法的想法会有帮助吗?

我认为您可以稍微简化
groupOthersKeeping
,方法是先拆分数组,然后根据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)
    )
 ]

使用更多的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]

我试着把它的功能用在大多数事情上。并将其保持为单管
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}))
)
const f=管道(
groupBy(道具(“国家”),
映射(映射(属性('value')),
地图(总和),
toPairs(),
sortBy(第(1)号提案),
反向(),
addIndex(map)((val,idx)=>idx({'country':a,'value':b}))
)


然而,我认为它不可读。

这是我的两分钱

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);

(每一步都会得到上一步的输出。最后所有的东西都会放在一起。)

步骤1:获取求和图

[
  [
    { country: "Hungary", value: 3},
    { country: "Albania", value: 4}
  ],
  [
    { country: "Spain", value: 130 },
    { country: "France", value: 200 },
    { country: "Romania", value: 500 },
    { country: "England", value: 800 }
  ]
]
您可以将其转换为:

[
  { 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'));
over(lensIndex(0), compose(map(countryFromPair), toPairs, reduceOthers));
第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 }
]
[
  { country: "Others", value: 7 },
  { 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 }
  ]
]
为此:

const reducer = reduceBy((sum, {value}) => sum + value, 0);
const reduceCountries = reducer(prop('country'));
over(lensIndex(0), compose(map(countryFromPair), toPairs, reduceOthers));
步骤5:展平整个阵列

[
  { country: "Hungary", value: 3 },
  { country: "Albania", value: 4 },
  { country: "Spain", value: 130 },
  { country: "France", value: 200 },
  { country: "Romania", value: 500 },
  { country: "England", value: 800 }
]
[
  { country: "Others", value: 7 },
  { country: "Spain", value: 130 },
  { country: "France", value: 200 },
  { country: "Romania", value: 500 },
  { country: "England", value: 800 }
]


完整的工作示例

以下是一种方法:

const combineAllBut=(n)=>pipe(下降(n)、下降(1)、总和、of、前置('Others')、of)
常量转换=管道(
groupBy(道具(“国家”),
映射(pull('value')),
地图(总和),
托帕尔斯,
排序(下降(第n(1)),
提升(混凝土)(取(4)、组合式提升(4)),
地图(zipObj(['country','value']))
)
const countries=[{国家:'法国',价值:100},{国家:'法国',价值:100},{国家:'罗马尼亚',价值:500},{国家:'英格兰',价值:400},{国家:'英格兰',价值:400},{国家:'西班牙',价值:130},{国家:'阿尔巴尼亚',价值:4},{国家:'匈牙利',价值:3}]
console.log(转换(国家))

const{pipe,groupBy,prop,map,pull,sum,of,prepend,toPairs,sort,down,nth,lift,concat,take,drop,zipObj}=ramda

我将按国家分组,将每个国家组合并为一个对象,同时对值求和、排序、拆分为两个数组[最高4]和[其他],将其他数组合并为一个对象,并将其与最高4合并

const{pipe,groupBy,prop,values,map,converge,merge,head,pull,sum,objOf,sort,down,splitAt,concat,last,of,assoc}=R
const sumProp=key=>pipe(拔出(key)、求和、对象(key))
const combineProp=key=>converge(合并,[head,sumProp(key)])
常量getTop5=管道(
groupBy(道具(“国家”),
值,//转换为国家/地区数组的数组
映射(combineProp('value'),//将每个子数组合并到单个对象
排序(下降(prop('value')),//按value属性对descebdubg进行排序
splitAt(4),//拆分为两个数组[4最高][其余]
converge(concat,[//合并最高的对象和其他对象
头,,
//将其余对象合并到数组中包装的其他对象
管道(最后一个,combineProp('value')、assoc('country'、'others')、of)
])
)
const countries=[{国家:'法国',价值:100},{国家:'法国',价值:100},{国家:'罗马尼亚',价值:500},{国家:'英格兰',价值:400},{国家:'英格兰',价值:400},{国家:'西班牙',价值:130},{国家:'阿尔巴尼亚',价值:4},{国家:'匈牙利',价值:3}]
const result=getTop5(国家)
console.log(结果)

我可能会这样做:

const aggregate=R.pipe(
R.groupBy(R.prop(‘国家’),
R.toPairs,
R.map(
R.applySpec({
国家:R.head,
值:R.pipe(R.last,R.pull('value'),R.sum),
}),
),
R.sort(R.down(R.prop('value'))),
R.splitAt(4),
R.完毕(
R.lensIndex(1),
R.applySpec({
国家:R.always(“其他”),
值:R.pipe(R.pull('value'),R.sum),
}),
),
R.unnest,
);
常数数据=[
{国家:'法国',值:100},
{国家:'法国',值:100},
{国家:'罗马尼亚',价值:500},
{国家:'英格兰',值:400},
{国家:'英格兰',值:400},
{国家:'西班牙',价值:130},
{国家:'阿尔巴尼亚',值:4},
{国家:'匈牙利',值:3}
];
console.log('结果',聚合(数据))
这里有两种解决方案 我认为第二个更容易理解,即使它更长

函数“mergeAllWithKeyBy”结合了“R.mergeAll”、“R.mergeWithKey”和“R.groupBy”的功能

const mergeAllWithKeyBy=R.curry((mergeFn,keyFn,objs)=>
R.values(R.reduceBy(R.mergeWithKey(mergeFn),{},keyFn,objs)))
常量addValue=(k,l,r)=>
k=='值'?l+r:r
常数getTop=
右管(
mergeAllWithKeyBy(附加值,R.prop(‘国家’),
R.sort(R.down(R.prop('value'))),
R.splitAt(4),
R.adjust(-1,R.map)(R.assoc(‘国家’、‘其他’)),
R.unnest,
mergeAllWithKeyBy(附加值,R.prop(‘国家’),
)
常数数据=[
{国家:'法国',值:100},
{国家:'法国',值:100},
{国家:'罗马尼亚',价值:500},
{国家:'英格兰',值:400},
{国家:'英格兰',值:400},
{国家:'西班牙',价值:130},
{国家:'阿尔巴尼亚',值:4},
{国家:'匈牙利',值:3}
]
console.log(getTop(data))

请添加您的代码,即使这是一种非常麻烦的方法,而且答案是否只需要使用该库的功能?我刚刚编辑了这个问题,以添加指向我的解决方案的可运行版本的链接。关于图书馆,我很高兴