如何通过第一个元素对象键对数组中的数组进行分组

时间:2019-05-30 11:38:49

标签: javascript arrays ecmascript-6

有这样一个数组数组:

    let arr = [
      [
        {"key":2, "other":123},
        {"key":2, "other":222}
      ],
      [
        {"key":3, "other":0}
      ],
      [
        {"key":1, "other":11},
        {"key":1, "other":23}
      ],
      [
        {"key":1, "other":22}
      ]
    ]

我需要获取此arr,但要使分组数组的第一个元素的“键”值相同,所以它看起来像:

  let arr = [
      [
        {"key":2, "other":123},
        {"key":2, "other":222}
      ],
      [
        {"key":3, "other":0}
      ],
      [
        [
          {"key":1, "other":11},
          {"key":1, "other":23}
        ],
        [
          {"key":1, "other":22}
        ]
      ],

    ]

我尝试使用reduce函数,但结果完全不同。

let final = []
  for (let i=0; i<arr.length; i++) {

    let arr1 = i==0?arr:arr.slice(i)

    let final1 = arr1.reduce((acc,x)=> {

      acc = acc[0].key==x[0].key?acc.concat(x):acc
      return acc
    })
    arr1.length>1&&final.push(final1)
  }

在此代码中,问题在于它将arr [1]与arr [2],arr [3]进行比较,然后再次将arr [2]与arr [3]进行比较并将其分组(即使arr [1] .key和arr [2] .key和arr [3] .key相同)您能给出一些提示或给出最终的功能吗?

4 个答案:

答案 0 :(得分:1)

创建keys的对象及其计数。然后,您可以过滤多次出现的键,即(count >= 2)。然后使用reduce遍历您的输入数组,并查看它存在于过滤后的数组键中,如果是,则推入单独的数组,其他为accu。然后将两个数组合并为一个。

let input = [
    [
      {"key":2, "other":123},
      {"key":2, "other":222}
    ],
    [
      {"key":3, "other":0}
    ],
    [
      {"key":1, "other":11},
      {"key":1, "other":23}
    ],
    [
      {"key":1, "other":22}
    ]
];

// keys with unique key and its count. filter whose count are greater than two.

const groupByArrKeysOccurence = input.reduce((accu, arr) => {
    const key = arr[0].key;
    accu[key] = (accu[key] || 0) + 1;
    return accu;
}, {});

const filteredKeys = Object.entries(groupByArrKeysOccurence).filter(([_, val]) => val > 1).map(([key, _]) => Number(key));

const multipleArrOccurenceKeys = [];

const singleArrOccurenceKeys = input.reduce((accu, arr) => {
    const isKey = arr.some(({key}) => filteredKeys.includes(key));
    if(isKey) {
        multipleArrOccurenceKeys.push(arr);
    } else {
        accu.push(arr);
    }
    return accu;
}, []);

console.log([...singleArrOccurenceKeys, multipleArrOccurenceKeys]);

答案 1 :(得分:1)

let arr = [
      [
        {"key":2},
        {"key":2}
      ],
      [
        {"key":3}
      ],
      [
        {"key":1},
        {"key":1}
      ],
      [
        {"key":1}
      ]
    ]
var myMap = new Map();
for (i = 0; i < arr.length; i++) { 
    if(!myMap.has(arr[i][0]['key'])){
        myMap.set(arr[i][0]['key'],i)
    }else if(myMap.get(arr[i][0]['key'])===undefined){

        myMap.set(arr[i][0]['key'],i)
    }else{
        myMap.set(arr[i][0]['key'],myMap.get(arr[i][0]['key'])+','+i)
    }
}
var out =[];
for(var v of myMap.values()){
    var s = String(v).split(",");
    var fi = s[0]
    var subarray =[]
    for(var i in s){
        subarray.push(arr[s[i]]) 
    }
    out[fi] = subarray;
}

您将在数组外找到响应。希望它对您有用

答案 2 :(得分:0)

我认为您想要这样的内容,请尝试运行代码段

let arr = [
    [
        {
            "key": 2
        },
        {
            "key": 2
        }
    ],
    [
        {
            "key": 3
        }
    ],
    [
        {
            "key": 1
        },
        {
            "key": 1
        }
    ],
    [
        {
            "key": 1
        }
    ]
]


let result = arr.reduce((res, array) => {
    array.forEach((value, index) => {
        const obj = res.find(a => {
            return !!a.find(({key}) => {
                return key === value.key
            })
        })
        if (obj) {
            obj.push(value)
        } else {
            res.push([value])
        }
    })
    return res;
}, [])


console.log(result);

答案 3 :(得分:0)

此解决方案无法产生您想要的确切结果,但是它很好而且干净。您想要的结果很可能会在将来给您带来麻烦,因为某些元素比其他元素嵌套得更多。

此答案假定每个数组始终至少有一个元素,因为问题是按第一个元素键分组。

let arr = [[{"key":2, "other":123}, {"key":2, "other":222}], [{"key":3, "other":0}], [{"key":1, "other":11}, {"key":1, "other":23}], [{"key":1, "other":22}]];

let groups = {};
let group = key => groups[key] || (groups[key] = []);
arr.forEach(arr => group(arr[0].key).push(arr));

console.log(groups);
console.log(Object.values(groups));

// If you want to get the result you're looking for (not looking at the
// order), you can simply flatten all groups of 1 element. Although
// depending on your use case I recommend sticking with the above.

console.log(Object.values(groups).map(group => group.length === 1 ? group[0] : group));