部分镜头:按 属性 对对象数组进行分组,使用道具值作为键
Partial Lenses: Group array of objects by property, use prop value as key
我有一个这样的对象数组:
[
{ name: "Group 1", value: "Foo" },
{ name: "Group 2", value: "Bar" },
{ name: "Group 1", value: "Baz" }
]
我想使用 Partial Lenses 库将这些组转换为具有相应组项的对象的键,如下所示:
{
"Group 1": [
{ name: "Group 1", value: "Foo" },
{ name: "Group 1", value: "Baz" }
],
"Group 2": [
{ name: "Group 2", value: "Bar" }
]
}
我目前的方法是这样的,假设我有一个名为 data
:
的变量中的源数据
const grouped = L.collect([L.groupBy('name'), L.entries], data)
const setKey = [L.elems, 0]
const getName = [L.elems, 1, 0, 'name']
const correctPairs = L.disperse(setKey, L.collectTotal(getName, grouped), grouped)
L.get(L.inverse(L.keyed), correctPairs)
我不喜欢我需要使用 grouped
和 correctPairs
变量来保存数据,因为我可能应该能够直接在合成中进行转换。你能帮助我以更有意义的方式组合相同的功能吗?
这是一个包含上述代码的 Partial Lenses Playground。
您可以使用Array.reduce
let arr = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
let obj = arr.reduce((a,c) => Object.assign(a, {[c.name]: (a[c.name] || []).concat(c)}), {});
console.log(obj);
您不需要任何库,使用 returns 缩减器的通用函数,这样您就可以使用任何键对任何集合进行分组。在下面的示例中,我使用它按名称分组,但也按值分组。
const groupBy = key => (result,current) => {
let item = Object.assign({},current);
// optional
// delete item[key];
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const data = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
const grouped = data.reduce(groupBy('name'),{});
console.log(grouped);
const groupedByValue = data.reduce(groupBy('value'),{});
console.log(groupedByValue);
我假设目标是实际创建一个同构,通过它可以
将这样的数组视为数组的对象并执行更新。像一个
例如的双向版本拉姆达的
R.groupBy
函数。
确实,一种方法是只使用 Ramda 的
R.groupBy
实现一个新的原语
使用 L.iso
的同构。
像这样:
const objectBy = keyL => L.iso(
R.cond([[R.is(Array), R.groupBy(L.get(keyL))]]),
R.cond([[R.is(Object), L.collect([L.values, L.elems])]])
)
需要条件来考虑数据不属于的可能性
预期的类型并将结果映射到 undefined
以防它不是。
这是一个基于上述 Ramda 的游乐场
objectBy
实施。
仅使用当前版本的Partial Lenses,一种合成类似的方法
objectBy
组合子如下:
const objectBy = keyL => [
L.groupBy(keyL),
L.array(L.unzipWith1(L.iso(x => [L.get(keyL, x), x], L.get(1)))),
L.inverse(L.keyed)
]
也许上面有趣的部分是中间的部分,将一个
数组的数组转换为键数组对的数组(或相反)。
L.unzipWith1
检查组中的所有键是否匹配,如果不匹配,则该组
将被映射到 undefined
并被过滤掉
L.array
。如果需要,
可以通过使用获得更严格的行为
L.arrays
.
这里是一个由上述组成的游乐场
objectBy
实施。
我有一个这样的对象数组:
[
{ name: "Group 1", value: "Foo" },
{ name: "Group 2", value: "Bar" },
{ name: "Group 1", value: "Baz" }
]
我想使用 Partial Lenses 库将这些组转换为具有相应组项的对象的键,如下所示:
{
"Group 1": [
{ name: "Group 1", value: "Foo" },
{ name: "Group 1", value: "Baz" }
],
"Group 2": [
{ name: "Group 2", value: "Bar" }
]
}
我目前的方法是这样的,假设我有一个名为 data
:
const grouped = L.collect([L.groupBy('name'), L.entries], data)
const setKey = [L.elems, 0]
const getName = [L.elems, 1, 0, 'name']
const correctPairs = L.disperse(setKey, L.collectTotal(getName, grouped), grouped)
L.get(L.inverse(L.keyed), correctPairs)
我不喜欢我需要使用 grouped
和 correctPairs
变量来保存数据,因为我可能应该能够直接在合成中进行转换。你能帮助我以更有意义的方式组合相同的功能吗?
这是一个包含上述代码的 Partial Lenses Playground。
您可以使用Array.reduce
let arr = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
let obj = arr.reduce((a,c) => Object.assign(a, {[c.name]: (a[c.name] || []).concat(c)}), {});
console.log(obj);
您不需要任何库,使用 returns 缩减器的通用函数,这样您就可以使用任何键对任何集合进行分组。在下面的示例中,我使用它按名称分组,但也按值分组。
const groupBy = key => (result,current) => {
let item = Object.assign({},current);
// optional
// delete item[key];
if (typeof result[current[key]] == 'undefined'){
result[current[key]] = [item];
}else{
result[current[key]].push(item);
}
return result;
};
const data = [{ name: "Group 1", value: "Foo" },{ name: "Group 2", value: "Bar" },{ name: "Group 1", value: "Baz" }];
const grouped = data.reduce(groupBy('name'),{});
console.log(grouped);
const groupedByValue = data.reduce(groupBy('value'),{});
console.log(groupedByValue);
我假设目标是实际创建一个同构,通过它可以
将这样的数组视为数组的对象并执行更新。像一个
例如的双向版本拉姆达的
R.groupBy
函数。
确实,一种方法是只使用 Ramda 的
R.groupBy
实现一个新的原语
使用 L.iso
的同构。
像这样:
const objectBy = keyL => L.iso(
R.cond([[R.is(Array), R.groupBy(L.get(keyL))]]),
R.cond([[R.is(Object), L.collect([L.values, L.elems])]])
)
需要条件来考虑数据不属于的可能性
预期的类型并将结果映射到 undefined
以防它不是。
这是一个基于上述 Ramda 的游乐场
objectBy
实施。
仅使用当前版本的Partial Lenses,一种合成类似的方法
objectBy
组合子如下:
const objectBy = keyL => [
L.groupBy(keyL),
L.array(L.unzipWith1(L.iso(x => [L.get(keyL, x), x], L.get(1)))),
L.inverse(L.keyed)
]
也许上面有趣的部分是中间的部分,将一个
数组的数组转换为键数组对的数组(或相反)。
L.unzipWith1
检查组中的所有键是否匹配,如果不匹配,则该组
将被映射到 undefined
并被过滤掉
L.array
。如果需要,
可以通过使用获得更严格的行为
L.arrays
.
这里是一个由上述组成的游乐场
objectBy
实施。