1

I want organize a 2 dimensional array. The array's values are object and I want to use a data in the value as key of new object/array.

The array I have:

let arr = [
  {name: 'Tom', class: A, sport: football},
  {name: 'Mary', class: C, sport: swimming},
  {name: 'Sam', class: B, sport: baseball},
  {name: 'Tom', class: A, sport: baseball},
  {name: 'Jim', class: B, sport: run},
  {name: 'Mary', class: C, sport: tennis}
]

The result I want:

let result = [
  Tom: [{class: A, sport: football}, {class: A, sport: baseball}],
  Mary: [{class: C, sport: swimming}, {class: C, sport: tennis}],
  Sam: [{class: A, sport: baseball}],
  Jim: [{class: B, sport: run}]
]

It doesn't matter the result is slight different from above. I just want organize the data by name and make that easily to use.

user4565857
  • 155
  • 1
  • 2
  • 9
  • 1
    Your wanted `result` is not possible, unless you want an object as result. Please, remember to include what you have tried also. – Shidersz Jun 11 '19 at 03:08
  • 1
    What you are asking for is a groupby operation. You will find this function available in common utility libraries like lodash or underscore. [Here](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-a-array-of-objects) is a groupby related answer. After they are grouped you just need to remove the `name` param from the objects in each array to get what you want. – Paul Rooney Jun 11 '19 at 03:24
  • @Shidersz Sorry, I was confused. Thank you. – user4565857 Jun 11 '19 at 06:35
  • @PaulRooney Thank you for telling me a name of what I am trying to do. I will learn about the libraries. – user4565857 Jun 11 '19 at 06:37

2 Answers2

2

As @Shidersz pointed, the exact expected output interposed cannot be obtained as it is against the definition of an array.

The following snippet applies a transform which the output is a slightly modified version of your expected output yet satisfying your need of organising the data by name.

arr.reduce(function (a, e, i, l) {
  return Object.assign(a, {
    [ e.name ]: a[e.name] && a[e.name].concat(e) || [ e ]
  });
}, {});
{
  Jim: [
    {name: "Jim", class: "B", sport: "run"}
  ],
  Mary: [
    {name: "Mary", class: "C", sport: "swimming"},
    {name: "Mary", class: "C", sport: "tennis"}
  ],
  Sam: [
    {name: "Sam", class: "B", sport: "baseball"}
  ],
  Tom: [
    {name: "Tom", class: "A", sport: "football"},
    {name: "Tom", class: "A", sport: "baseball"}
  ]
}

Alternately, a utility libraries could be used to obtain a similar transformation as pointed out by @Paul

Ashen Gunaratne
  • 435
  • 3
  • 9
  • Thank you for your clear explanation. I can get what I want. Eslint said do not mix && and ||, so I changed `[ e.name ]: a[e.name] && a[e.name].concat(e) || [ e ]` to `[ e.name ]: (a[e.name] && a[e.name].concat(e)) || [ e ]`. It works! Perfect! – user4565857 Jun 11 '19 at 07:22
0

Here is another way using a groupby operation and then mapping the values of the object to not include the name property.

let input = [
  {name: 'Tom',  class: 'A', sport: 'football'},
  {name: 'Mary', class: 'C', sport: 'swimming'},
  {name: 'Sam',  class: 'B', sport: 'baseball'},
  {name: 'Tom',  class: 'A', sport: 'baseball'},
  {name: 'Jim',  class: 'B', sport: 'run'},
  {name: 'Mary', class: 'C', sport: 'tennis'}
];

/**
 * group elements in an array by the result of some key function.
 * @param {array} arr The array to group.
 * @param {function} keyFn  the function returning the value to group on.
 */
function groupByKey(arr, keyFn) {
    const result = {};

    for(let a of arr) {
        const grouper = keyFn(a);
        if(grouper in result) result[grouper].push(a);
        else                  result[grouper] = [a];
    }
    return result;
}

/**
 * Map objects values, leaving the keys untouched.
 * @param {object} ob The object to have its values mapped.
 * @param {function} mapFn The function to perform the mapping.
 */
function mapValues(ob, mapFn){
    const result = {};

    for (let k of Object.keys(ob)) {
        result[k] = mapFn(ob[k]);
    }
    return result;
}

console.log(
    mapValues(
        groupByKey(input, x => x.name),
        x => x.map(y => ({class: y.class, sport: y.sport}))
    )
);
Paul Rooney
  • 20,879
  • 9
  • 40
  • 61