1

Got an array of arrays like this:

    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}
      ]
    ]

I need to get this arr but with grouped arrays with the same "key" value of the first element so it will be look like:

  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}
        ]
      ],

    ]

I tried to use reduce function, but the result was totally different.

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

In this code the problem is that it compares arr[1] with arr[2], arr[3] and then again arr[2] with arr[3] and groups it(even though arr[1].key and arr[2].key and arr[3].key are the same) Can you give some tips or give the final function to do this?

5
  • 4
    Why did you chose that structure at all? What is the usecase behind it? This sounds like an XY problem. Commented May 30, 2019 at 11:41
  • 2 arrays where objects have the same key value are grouped into array:[array, array] Commented May 30, 2019 at 11:42
  • 3
    that's a weird dataset, I can't foresee any advantage of such a structure, neither for performances, neither for readability. Commented May 30, 2019 at 11:43
  • 3
    yes I see that. but why? Why not [{ key: 1, count: 2 }, ...] ? Commented May 30, 2019 at 11:43
  • I get JSON response from API and I need to group it to show in blocks. The structure of initial array is the result of first level grouping, and the task is the second one in order to list them in divs like I need Commented May 31, 2019 at 4:21

4 Answers 4

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

You will find your response in out array. Hope that it works for you

Sign up to request clarification or add additional context in comments.

Comments

1

Create the object of keys along with its count. Then you can filter the keys which are present more than once i:e (count >= 2). Then iterate over your input array using reduce and see it is present within the filtered array keys, if yes then push in separate array and other is accu. Then merge the two arrays into one.

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 Comment

That does work with the example, however if we modify input array's first array from [ {"key":2, "other":123}, {"key":2, "other":222} ] to [ {"key":3, "other":123}, {"key":3, "other":222} ], the final array length should be 2, first array with key=3, and second with key=1
0

I think you want something like this, try running the snippet

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

Comments

0

This solution doesn't produce the exact result you're looking for, but it is nice and clean. The result you want is most likely going to give you some trouble in the future, since some elements are further nested than others.

This answer assumes that each array always has at least one element, since the question is to group by the first element key.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.