如何将数组转换为对象,其名称是数组中的第一个值,属性是子数组的数组?



获取具有未知元素列表的多维数组并将其分组到一个对象中以删除子数组第一个元素中的重复值的最佳方法是什么:

例如,我想把这个变成:

const arr = [[a, 1, 4], [b, 3, 4], [c, 1, 7], [a, 2, 5], [c, 3, 5]]

进入这个:

arrResult = {a:[[1, 4],[2, 5]], b:[[3, 4]], c:[[1, 7],[3, 5]]}

我想过对此进行排序,然后将其拆分或运行某种归约操作,但无法确切地弄清楚如何完成它。

只需要使用 reduce(和切片),无需排序或拆分

var arr = [['a', 1, 4], ['b', 3, 4], ['c', 1, 7], ['a', 2, 5], ['c', 3, 5]];
var arrResult = arr.reduce((result, item) => {
var obj = result[item[0]] = result[item[0]] || [];
obj.push(item.slice(1));
return result;
}, {});
console.log(JSON.stringify(arrResult));

你可以像这样使用reduce

const arr = [["a", 1, 4], ["b", 3, 4], ["c", 1, 7], ["a", 2, 5], ["c", 3, 5]];
var result = arr.reduce((obj, sub) => {
var key = sub[0];                         // key is the first item of the sub-array
if(obj[key]) obj[key].push(sub.slice(1)); // if the there is already an array for that key then push this sub-array (sliced from the index 1) to it
else obj[key] = [sub.slice(1)];           // otherwise create a new array that initially contain the sliced sub-array
return obj;
}, {});
console.log(result);

你可以像这样使用reducedestructuring

const arr = [['a', 1, 4],['b', 3, 4],['c', 1, 7],['a', 2, 5],['c', 3, 5]]
function sub(arr) {
return arr.reduce((obj, [key, ...value]) => {
obj[key] ? obj[key].push(value) : obj[key] = [value]
return obj
}, {})
}
console.log(sub(arr));

我更喜欢这个解决方案,因为它抽象了排序规则,但允许您使用高阶函数控制项目的排序方式。

请注意,我们在collateBy函数中根本不谈论数据的种类或结构——这使我们的函数保持通用,并允许它处理任何形状的数据。

// generic collation procedure
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
// generic head/tail functions
const head = ([x,...xs]) => x
const tail = ([x,...xs]) => xs
// collate by first element in an array
const collateByFirst = collateBy (head)
// your custom function, using the collateByFirst collator
// this works much like Array.prototype.reduce
// the first argument is your accumulator, the second argument is your array value
// note the acc=[] seed value used for the initial empty collation
const foo = collateByFirst ((acc=[], xs) => [...acc, tail(xs)])
const arr = [['a', 1, 4], ['b', 3, 4], ['c', 1, 7], ['a', 2, 5], ['c', 3, 5]]
let collation = foo(arr);
console.log(collation.get('a')) // [ [1,4], [2,5] ]
console.log(collation.get('b')) // [ [3,4] ]
console.log(collation.get('c')) // [ [1,7], [3,5] ]

当然,如果您不想为中间函数命名,则可以将其全部写在一行中

let collation = collateBy (head) ((acc=[], xs) => [...acc, tail(xs)]) (arr)
console.log(collation.get('a')) // [ [1,4], [2,5] ]

最后,如果需要对象,只需将Map类型转换为对象即可

let obj = Array.from(collation).reduce((acc, [k,v]) =>
Object.assign(acc, { [k]: v }), {})
console.log(obj)
// { a: [ [1,4], [2,5] ],
//   b: [ [3,4] ],
//   c: [ [1,7], [3,5] ] }

高阶函数演示了像collateBy这样的泛型过程是多么强大。下面是另一个使用完全相同的collateBy过程但执行非常不同的排序规则的示例

const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
const collateEvenOdd = collateBy (x => x % 2 === 0 ? 'even' : 'odd')
const sumEvenOdd = collateEvenOdd ((a=0, b) => a + b)
let data = [2,3,4,5,6,7]
let collation = sumEvenOdd (data)
let even = collation.get('even')
let odd = collation.get('odd')
console.log('even sum', even) // 2 + 4 + 6 === 12
console.log('odd sum', odd)   // 3 + 5 + 7 === 15

相关内容

最新更新