Related
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
Into
const myCollection = [
{a: 1, b: 2, c: 10},
{a: 2, b: 4, c: 20},
{a: 3, b: 6, c: 30}
]
I tried combinations of Object.entries, Object.keys and map but I'm always finding myself iterating twice or more over myObj and I'm not happy with any solution I came up with.
So what is the most efficient (in terms of time complexity) and elegant way that you can think to achieve that?
Just in case you'd need variable length:
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6,8, 10],
c: [10, 20, 30, 40],
};
let myCollection = [];
Object.keys(myObj).forEach((k) => {
for (let i = 0; i < myObj[k].length; i++) {
if (!myCollection[i]) myCollection.push({});
myCollection[i][k] = myObj[k][i];
}
});
console.log(myCollection);
You could reduce the entries and map nested arrays.
const
object = { a: [1, 2, 3], b: [2, 4, 6], c: [10, 20, 30] },
result = Object
.entries(object)
.reduce((r, [k, a]) => a.map((v, i) => ({ ...r[i], [k]: v })), []);
console.log(result);
That can be done using Array.reduce. I have attached the conversion code.
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
const myCollection = [
{a: 1, b: 2, c: 10},
{a: 2, b: 4, c: 20},
{a: 3, b: 6, c: 30}
]
const maxLength = Math.max(...Object.values(myObj).map(item => item.length));
const myObjKeys = Object.keys(myObj);
const result = [ ...Array(maxLength).keys() ].map((index) => {
return myObjKeys.reduce((acc, curKey) => {
if (myObj[curKey].length > index) {
acc[curKey] = myObj[curKey][index];
}
return acc;
}, {});
});
console.log(result);
Using ramdajs, I could suggest you a short way like below
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
const res = R.map(
R.zipObj(R.keys(myObj)),
R.values(myObj)
)
console.log(res)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
In ramdajs homepage, criteria 3 in What's Different, it cited that
The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.
You can use map() on Object.values and then use reduce() on each value.
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
let keys = Object.keys(myObj);
const arr = Object.values(myObj).map((a) => a.reduce((ac, a, i) => ({...ac, [keys[i]]:a}), {}));
console.log(arr)
Suppose I have:
const KEYS = ['b', 'a', 'c']
const obj = {
2018: {a: 1, b: 2, c: 3},
2019: {a: 4, b: 5, c: 6},
2020: {a: 7, b: 8, c: 9},
}
This is what I would like to get:
const result = {
2018: {
a: [0, 1, 0],
b: [2, 0, 0],
c: [0, 0, 3]
},
2019: {
a: [0, 4, 0],
b: [5, 0, 0],
c: [0, 0, 6]
},,
2020: {
a: [0, 7, 0],
b: [8, 0, 0],
c: [0, 0, 9]
},
}
result['2018'] object has three keys. Each key value is an array that contains the values in the order that is set by KEYS using 0 as fill value.
How can I do something like this?
This is what I tried but obviously is more complicated than this:
const reshaped = Object.entries(obj).map(([key, value]) => {
return { [key]: Object.values(value) }
})
// [
// { 2018: [ 1, 2, 3 ] },
// { 2019: [ 4, 5, 6 ] },
// { 2020: [ 7, 8, 9 ] }
// ]
You could map the wanted keys in order abd build an array for each property.
const
KEYS = ['b', 'a', 'c'],
object = { 2018: { a: 1, b: 2, c: 3 }, 2019: { a: 4, b: 5, c: 6 }, 2020: { a: 7, b: 8, c: 9 } },
result = Object.fromEntries(Object.entries(object).map(([k, o]) => [
k,
Object.fromEntries(Object.entries(o).map(([l, v]) => [
l,
KEYS.map(m => l === m ? v : 0)
]))
]));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use a combination of Object.entries and Object.fromEntries to map the object and then just create a new array with the length of the KEYS arr.
const KEYS = ['b', 'a', 'c']
const obj = {
2018: {a: 1, b: 2, c: 3},
2019: {a: 4, b: 5, c: 6},
2020: {a: 7, b: 8, c: 9},
}
const result = Object.fromEntries( // Create obj from array of entries
Object.entries(obj).map(([key, value]) => [ // create array of entries from obj and map it
key,
Object.fromEntries( // do the same obj/arr transformation on the value
Object.entries(value).map(([subKey, subValue]) => {
const arr = new Array(KEYS.length).fill(0); // create new array of keys length and fill all zeroes
arr[KEYS.indexOf(subKey)] = subValue; // on the index of the key in the KEYS arr, set the value of the key
return [subKey, arr]; // return subValue
})
)
])
);
console.log(result);
This question already has answers here:
Sort JavaScript object by key
(37 answers)
Closed 4 years ago.
I have the following array of object :
var wordSpecsArr = [{a: 2, b: 2},{a: 1, b: 1, c: 1, d: 1},{b: 2, a: 2},{d: 2, a: 2},{a: 2, b: 2}]
and I would like to sort each object by keys so that it will become:
var wordSpecsArr = [{a: 2, b: 2},{a: 1, b: 1, c: 1, d: 1},{a: 2, b: 2},{a: 2, d: 2},{a: 2, b: 2}]
I have tried the following code:
//sort keys
wordSpecsArr.forEach((obj) => {
var ordered = {};
Object.keys(obj).sort().forEach((key) => {
ordered[key] = obj[key]
});
});
But it did not work. I would really appreciate any help
Try this.
var wordSpecsArr = [{a: 2, b: 2},{a: 1, b: 1, c: 1, d: 1},{b: 2, a: 2},{d: 2, a: 2},{a: 2, b: 2}]
var wordSpecsArr = [{a: 2, b: 2},{a: 1, b: 1, c: 1, d: 1},{a: 2, b: 2},{a: 2, d: 2},{a: 2, b: 2}]
//sort keys
let op =[];
wordSpecsArr.forEach((obj) => {
let ordered = {};
Object.keys(obj).sort().forEach((key) => {
ordered[key] = obj[key]
});
op.push(ordered)
});
console.log(op)
say I have this most basic object
var x = {
a: 1,
b: 2,
c: 3,
d: 4
}
if I do this Object.values(x) this returns me an array of the values [1, 2, 3, 4]
how can I do this in lodash?
I know i can use get
_.get(x)
is just returning me undefined. I want the same thing as Object.values returns me but using lodash
Use _.values
var x = {a: 1,b: 2,c: 3,d: 4};
var result = _.values(x);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Just take _.values.
var x = { a: 1, b: 2, c: 3, d: 4 };
console.log(_.values(x));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
try with
var x = {
a: 1,
b: 2,
c: 3,
d: 4
}
const result = _.values(x);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
Reference:
https://lodash.com/docs/4.17.10#values
Say I have an array of 3 objects like this:
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
},
{
a: 2,
b: 3,
c: 3
}
]
I would like to return an array of arrays containing the objects that share a common value for the property b. So the resulting array would contain only one array containing 2 objects like this:
[
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
}
]
]
How would I do this?
You could do this with map and filter
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}];
var check = data.map(e => {return e.b});
var result = [data.filter(e => { return check.indexOf(e.b) != check.lastIndexOf(e.b)})];
console.log(result)
To group multiple objects in separate arrays with same b values you can use map and forEach
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}, {"a":3,"b":7,"c":6},{"a":2,"b":7,"c":3}], result = [];
var check = data.map(e => {return e.b});
data.forEach(function(e) {
if(check.indexOf(e.b) != check.lastIndexOf(e.b) && !this[e.b]) {
this[e.b] = [];
result.push(this[e.b]);
}
(this[e.b] || []).push(e);
}, {});
console.log(result)
This proposal uses a single loop with Array#forEach but without Array#indexOf.
var array = [{ a: 4, b: 5, c: 4 }, { a: 3, b: 5, c: 6 }, { a: 2, b: 3, c: 3 }],
grouped = [];
array.forEach(function (a) {
this[a.b] = this[a.b] || [];
this[a.b].push(a);
this[a.b].length === 2 && grouped.push(this[a.b]);
}, Object.create(null));
console.log(grouped);
You can create a function that accepts fulfillment criteria and will return as many nested arrays as rules passed.
Let's say you have an array of objects, arr.
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
And you want to return an array with with nested arrays that fulfill a particular requirement, let's say you want objects with an a:1 and b:2.
You can create a function that loops through your rules and creates a nested array with the objects that fulfill each rule.
For example:
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
function makeNestedArrays() {
var rules = [].slice.call(arguments);
return rules.reduce(function(acc, fn) {
var nestedArr = [];
arr.forEach(function(obj) {
if (fn(obj)) {
nestedArr.push(obj);
}
});
// only push nested array
// if there are matches
if (nestedArr.length) {
acc.push(nestedArr);
}
return acc;
}, []);
}
var result = makeNestedArrays(
function(obj) { return obj.a === 1; },
function(obj) { return obj.b === 2; }
);
console.log(result);
This allows you to pass as many "rules" as you want, and will create a nested array for each rule so long as there is at least one match.
You could use a Map to group them, this should work with any kind of value (just be sure the equality rules check out):
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
console.log(...(result.values()));
If you'd need to filter out the groups of 1:
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
result = [...result.values()].filter(a => a.length > 1);
console.log(result);