This question already has answers here:
How to get a subset of a javascript object's properties
(36 answers)
Closed 2 years ago.
I have a bit JSON object with over 50 keys like
const data = {a:1, b:2, c:3,....,y:99,z:100}
and 2 arrays containing keys of this json object
const arr1 = ["a", "b", "m", "l", "x", "y", "Z"]
const arr2 = ["c", "d", "g", "h", "i", "k", "q"]
Now I want to copy all the value from data object into 2 new objects which contain only data of those keys which are present in arr1 and arr2 into 2 objects
const data = { a: 1, b: 2, c: 3, d: 4, y: 99, z: 100 };
const arr1 = ['a', 'b', 'm', 'l', 'x', 'y', 'Z'];
const arr2 = ['c', 'd', 'g', 'h', 'i', 'k', 'q'];
const res1 = arr1.map(item => ({ [item]: data[item] }));
const res2 = arr2.map(item => ({ [item]: data[item] }));
console.log(res1);
console.log(res2);
Maybe you can try, is very easy and there are a lot of ways to do.
var valuesFromArr1 = arr1.map(key => data[key]);
If you want all your keys in a single object, consider using an Array reduce method. Here I abstracted it into a reusable function and applied it to each of your desired arrays.
const data = {a:1, b:2, c:3, y:99, z:100};
const arr1 = ["a", "b", "c"];
const arr2 = ["c", "y", "z"];
function arrToData(arr, data) {
return arr.reduce((acc, el) => {
acc[el] = data[el];
return acc;
}, {});
}
console.log(
arrToData(arr1, data),
arrToData(arr2, data)
);
Related
This question already has answers here:
How to get sub-arrays containing same elements from an array?
(2 answers)
Closed 1 year ago.
I have:
['a', 'b', 'd', 'a', 'f', 'b', 'a', 'b']
I'd like to have:
[['a', 'a', 'a'], ['b', 'b', 'b'], ['d'], ['f']]
You can do it like this:
const test = ["a", "b", "d", "a", "f", "b", "a", "b"]
function parseElements(elements) {
const temp = {}
for (const element of test) {
if (!temp[element]) {
temp[element] = []
}
temp[element].push(element)
}
return [...Object.values(temp)]
}
const result = parseElements(test)
I have an array of elements and I want to get the frequency of the elements in an array, which is fine. How do I convert the object to store these elements and frequencies in a format to have property names or keys
var array = ['a','a','a','b','b','c','d','d','d','d',]
obj = [{ element: 'a', frequency: 3},
{ element: 'b', frequency: 2},
{ element: 'c', frequency: 1},
{ element: 'd', frequency: 4}]
Right now I have a solution that just returns:
obj = { a : 3, b : 2, c : 1, d : 4 }
You can convert it using Object.entries like below.
const obj = {
a: 3,
b: 2,
c: 1,
d: 4
};
const target = Object.entries(obj).map(v => ({
element: v[0],
frequency: v[1]
}));
console.log(target);
You can use Array#map on Object.entries with destructuring.
const obj = { a : 3, b : 2, c : 1, d : 4 };
const res = Object.entries(obj).map(([element,frequency])=>({element,frequency}));
console.log(res);
Using a map for quick & easy access while you compute the frequencies is a good idea but what stops you from creating the desired objects directly?
e.g. instead of
{ a: 3
, b: 2
}
Why not?
{ a: {element: 'a', frequency: 3}
, b: {element: 'b', frequency: 2}
}
You then simply need to Object.values(obj) to get what you want.
const freq =
xs =>
Object.values
( xs.reduce
( (acc, x) =>
( acc[x] = acc[x] || {element: x, frequency: 0}
, acc[x].frequency += 1
, acc
)
, {}
)
);
console.log(freq(['a','a','a','b','b','c','d','d','d','d']));
I have an array that looks like:
[
["A","B","C","D"],
["E","F","G","H"],
[6,43,2,4]
]
I want to sort this array in descending order of the items in the third row, such that it looks like:
[
["B","A","D","C"],
["F","E","H","G"],
[43,6,4,2]
]
So far this is what I wrote:
var arr = [
["A","B","C","D"],
["E","F","G","H"],
[6,43,2,4]
]
arr = arr.sort((a,b) => {
return b[2] - a[2]
});
console.log(arr);
But the array does not get sorted. Where did I go wrong?
You could take the indices of the array for sorting, sort this array by the values of the original array and map all reordered items.
var array = [["A", "B", "C", "D"], ["E", "F", "G", "H"], [6, 43, 2, 4]],
indices = [...array[2].keys()].sort((a, b) => array[2][b] - array[2][a]);
array = array.map(a => indices.map(i => a[i]));
console.log(array.map(a => a.join(' ')));
You want to sort columns. It is easier to sort rows. So, you could transpose then sort then retranspose:
const arr = [
["A","B","C","D"],
["E","F","G","H"],
[6,43,2,4]
];
const transpose = array => array[0].map((col, i) => array.map(row => row[i]));
const t = transpose(arr);
t.sort((rowi,rowj) => (rowj[rowj.length - 1] - rowi[rowi.length-1]));
console.log(transpose(t));
Which has the intended output of:
[ [ 'B', 'A', 'D', 'C' ],
[ 'F', 'E', 'H', 'G' ],
[ 43, 6, 4, 2 ] ]
This is clearly not as efficient as the other answers, but the fact that you are asking the question suggests that your current way of storing the data isn't convenient for your purposes. Perhaps you might want to transpose then skip the retranspose part.
You need to first sort the number store indexes and then sort the other arrays.
var arr = [
["A","B","C","D"],
["E","F","G","H"],
[6,43,2,4]
]
var tmp = arr[2].map((value, i) => ({value, i})).sort((a, b) => b.value - a.value);
arr = arr.map(function(arr) {
return tmp.map(({value, i}) => arr[i]);
});
console.log(arr);
It would be easier if you could depict the data differently. The Array.sort function will not help you with your current example.
var arr = [{
a: "A", b: "E", c: 6
},{
a: "B", b: "F", c: 43
},{
a: "C", b: "G", c: 2
},{
a: "D", b: "H", c: 4
}]
arr.sort((a, b) => {
return b.c - a.c;
})
console.log(arr);
If you can't, I could provide a different answer; but the answer would be very inefficient.
I'm trying to duplicate each element in an array, but using functional style.
I have this currently:
["a", "b", "c"]
And I'm getting this:
["a","a","b","b","c","c"]
So far I have tried the following, mapping each element to an array, then using flat() to get a 1d array. Is there a cleaner way because it feels like I'm abusing map and flat.
["a", "b", "c"].map(item => [item, item]).flat();
Is there a better way to do this?
I was trying to provide a example as simple as possible but left some details out. The real input is not sorted because elements are not comparable.
It's something like:
[
{
a:"a"
b:"b"
},
{
c: 1
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
]
The duplicated result should be something like this, where duplicated elements are next to each other:
[
{
a:"a"
b:"b"
},
{
a:"a"
b:"b"
},
{
c: 1
d: 2
},
{
c: 1
d: 2
},
{
apple: {},
sellers: ["me", "her"]
},
{
apple: {},
sellers: ["me", "her"]
}
]
Array.reduce is semantically the appropriate method here: take an object (in this case an array) and return an object of a different type, or with a different length or shape (note: edited to use Array.push for faster performance per #slider suggestion):
EDIT: I've edited my answer to reflect OP's updated input data. Note also, that this solution is cross-browser and NodeJS compatible without requiring transpilation.
let data = [
{
a:"a",
b:"b",
},
{
c: 1,
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
];
let result = data
.reduce((acc, el) => {
acc.push(el, el);
return acc;
}, []);
console.log(JSON.stringify(result, null, 2));
Otherwise you could map each element, duplicating it, then combine them:
let data = [
{
a:"a",
b:"b",
},
{
c: 1,
d: 2
},
{
apple: {},
sellers: ["me", "her"]
}
];
let result = data.map(item => [item, item]).reduce((acc, arr) => acc.concat(arr));
console.log(JSON.stringify(result, null, 2));
As mentioned in other answers here, either of these approaches have the advantage of not requiring the original array to have been sorted.
You can use the function reduce and concatenate the same object on each iteration.
let array = ["a", "b", "c"],
result = array.reduce((a, c) => a.concat(c, c), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would recommend Array.prototype.flatMap -
const twice = x =>
[ x, x ]
console .log
( [ 'a', 'b', 'c' ] .flatMap (twice) // [ 'a', 'a', 'b', 'b', 'c', 'c' ]
, [ 1, 2, 3, 4, 5 ] .flatMap (twice) // [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]
)
flatMap is useful for all kinds of things -
const tree =
[ 0, [ 1 ], [ 2, [ 3 ], [ 4, [ 5 ] ] ] ]
const all = ([ value, ...children ]) =>
[ value ] .concat (children .flatMap (all))
console .log (all (tree))
// [ 0, 1, 2, 3, 4, 5 ]
really cool things -
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
console .log
( ranks .flatMap (r =>
suits .flatMap (s =>
[ [ r, s ] ]
)
)
)
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
flatMap is just a specialised Array.prototype.reduce and is easy to implement in environments where Array.prototype.flatMap is not already supported -
const identity = x =>
x
const flatMap = (xs = [], f = identity) =>
xs .reduce ((r, x) => r . concat (f (x)), [])
const ranks =
[ 'J', 'Q', 'K', 'A' ]
const suits =
[ '♡', '♢', '♤', '♧' ]
console.log
( flatMap (ranks, r =>
flatMap (suits, s =>
[ [ r, s ] ]
)
)
)
// [ ['J','♡'], ['J','♢'], ['J','♤'], ['J','♧']
// , ['Q','♡'], ['Q','♢'], ['Q','♤'], ['Q','♧']
// , ['K','♡'], ['K','♢'], ['K','♤'], ['K','♧']
// , ['A','♡'], ['A','♢'], ['A','♤'], ['A','♧']
// ]
You could just do this:
var arr = ["a", "b", "c"];
arr = arr.concat(arr).sort();
This is one of the simplest methods to do what you are asking to do.
The simplest solution is to use flatMap():
const source = ["a", "b", "c"];
const result = source.flatMap(item => [item, item]);
[ 'a', 'a', 'b', 'b', 'c', 'c' ]
A little bit of classic:
let source = ["a", "b", "c"];
const originalLength = source.length;
for(let i = 0; i <= originalLength + (originalLength - 2); i++) {
source.splice(i, 0, source[i++]);
}
[ 'a', 'a', 'b', 'b', 'c', 'c' ]
myArr = ['a', 'b', 'c' ];
myArr.reduce((obj, val) => ({ ...obj, [val]: val }));
Based on my understanding, you would expect the reduce to return { a: 'a', b: 'b', c: 'c' }
What we actually get back is { 0: 'a', b: 'b', c: 'c' }
I tried putting a log inside to see what is going on with that first item, but the output is:
b
c
{0: "a", b: "b", c: "c"}
So now the behaviour is even more strange because we don't get any logs for the first val iteration.
let myArr = ['a', 'b', 'c' ];
let result = myArr.reduce((obj, val) => ({ ...obj, [val]: val }), {});
console.log(result);
You missed the initial value to reduce. When no initial value is supplied, reduce pops off the first element for this purpose (and indeed no iteration happens; because 1+2+3 has two additions, not three, unless you specify we have to start from 0).
The first element is "a", which deceptively becomes the misnamed obj; when you execute {..."a", b: "b"}, you will see that ..."a" expanded in the object context will yield the characters' index as the key; thus, ..."a" is equivalent to ...{0: "a"}.
Good thing you didn't try with myArr = ['hello', 'world'] - that'd be much more of a surprise, I imagine (the result from that being {0: "h", 1: "e", 2: "l", 3: "l", 4: "o", world: "world"}).