0

I want to reorder this array:

[{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}]

to this:

{a: ["v1", "v3"] , b: ["v2", "v4"]}

Note: It is necessary to guarantee order, the first array element should be the first element in the array value in each key object

4
  • What is your question? Commented Mar 26, 2017 at 17:24
  • a shorten solution Commented Mar 26, 2017 at 17:25
  • Do you accept pure js solution? Commented Mar 26, 2017 at 17:27
  • yes, no problem Commented Mar 26, 2017 at 17:29

5 Answers 5

1

Pure js solution, using Array#forEach and Object.keys.

var arr = [{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}],
    obj = {};
    
    arr.forEach(c => Object.keys(c).forEach(function(v){
      (obj[v] || (obj[v] = [])).push(c[v]);
    }));
    
    console.log(obj);
        

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

Comments

0

An extended Version of @Kind user's code, that also deals with objects that have different keys:

function mapByKey(source){
  var result = Object.create(null);
  source.forEach((item, index) => {
    if(item == null) return;
    Object.keys(item).forEach(key => {
      if(!(key in result)){
        //don't use sparse Arrays
        result[key] = Array(source.length).fill(undefined); 
      }

      result[key][index] = item[key];
    })
  })
  return result;
}

var array = [
  {a: "v1", b: "v2"}, 
  {a: "v3", c: "v4"}, 
  {b: "v5", c: "v7"}
];
var mapping = mapByKey(array);

console.log(mapping);

//or something funny:
console.log(mapByKey(["foo", "bar", "baz", "asdf"]));

The point of this version, is that even if your Array contains Objects with different keys (like in the example, one object has a and b, one has a and c and one has b and c), this will always be true:

array[index][key] === mapping[key][index];

2 Comments

that also deals with objects that have different keys - my code doesn't? (:
@Kinduser, maybe I misinterpreted the OTs request for guaranteed order as a request for a strict mapping: array[index][key] === mapping[key][index]. That's the difference between our two codes. Your code returns a list of values by key, mine a strict mapping. Let's see what the OT actually needs.
0

Alternative solution using Array.prototype.reduce() and Object.keys() function:

var arr = [{ a: "v1", b: "v2"} , {a: "v3", b: "v4"}],
    result = arr.reduce(function (r, o) {
        Object.keys(o).forEach(function(k){ (r[k])? r[k].push(o[k]) : r[k] = [o[k]]; });
        return r;
    }, {});

console.log(result);

Comments

0

Here's a lodash solution that uses the combination of spread and mergeWith to merge all the objects with similar properties.

var result = _.spread(_.mergeWith)([{}].concat(data, 
  _.flow(_.ary(_.concat, 2), _.compact)
));

var data = [{
  a: "v1",
  b: "v2"
}, {
  a: "v3",
  b: "v4"
}, {
  a: "v5",
  b: "v6",
  c: "1"
}];

var result = _.spread(_.mergeWith)([{}].concat(data, 
  _.flow(_.ary(_.concat, 2), _.compact)
));

console.log(result);
body>div {
  min-height: 100%;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Comments

0

Another (short) lodash solution, using a combination of reduce and mergeWith:

_.reduce(data, (acc, x) => _.mergeWith(acc, x, 
                                            (obj = [], src) => obj.concat(src)),
         {});

Or a bit more readable:

const customizer = (obj = [], src) => obj.concat(src);
_.reduce(data, (acc, x) => _.mergeWith(acc, x, customizer), {});

Or even:

const customizer = (obj = [], src) => obj.concat(src);
_.reduce(data, _.partialRight(_.mergeWith, customizer), {});

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.