I can't be able to figure out how to push items to same nested array like :
var arr = ['foo', 'bar', 'buz', 'hello'];
// It should be now look like this:
const output = {name: 'foo', children: [
{name: 'bar', children: [
{name: 'buz', children: [
{name: 'hello', children: []}
]}
]}
]};
Using reduce:
const arr = ['foo', 'bar', 'buz', 'hello'];
const result = arr.reverse().reduce((acc, val) => ({name: val, children: [acc]}), {});
console.log(result);
You can use reduceRight to create the output.
var arr = ['foo', 'bar', 'buz', 'hello'],
result = arr.reduceRight((r, name) => ({name, children: (!Object.keys(r).length ? [] : [r])}), {});
console.log(result);
Using a recursive function:
const arr = ['foo', 'bar', 'buz', 'hello'];
const f = (arr) => ({name: arr.shift(), children: arr.length ? [f(arr)] : []});
const output = f(arr);
console.log(output);
Using a recursive function
function nested (arr) {
if (arr.length === 1)
return { name: arr.shift(), children: [] };
else if (arr.length > 1)
return { name: arr.shift(), children: [nested(arr)] };
}
var array = ['foo', 'bar', 'buz', 'hello']
console.log(nested(array))
I now have an idea on how Array.reduce() method work, so posted another answer without recursive approach. I think it would be better for large tree structure.
The basic idea is that simply reverse the input array and then wrap the innermost object into another and so on.
let arr = ['foo', 'bar', 'buz', 'hello'];
function nest(arr) {
arr = arr.reverse();
let out = [];
arr.forEach(it => {
if(out.length === 0) out = {name: it, children: []}
else {
out = {name: it, children: [out]}
}
});
return out;
}
Related
My initial data is coming like this..
let initial = {
labels: ['label1', 'label2', 'label3'],
children: ['child1', 'child2', 'child3'],
numbers: [1 , 2 , 3]
};
I need output in this format..
FINAL_OUTPUT = [
{ labels: 'label1', children: 'child1', numbers: 1 },
{ labels: 'label2', children: 'child2', numbers: 2 },
{ labels: 'label3', children: 'child3', numbers: 3 }
];
Separated the keys and values from the initial object. But struck in creating array of objects from the same. Please help.
You could get the entries and map the inner array with the values at the given index.
let initial = { labels: ['label1', 'label2', 'label3'], children: ['child1', 'child2', 'child3'], numbers: [1, 2, 3] },
result = Object
.entries(initial)
.reduce((r, [k, a]) => a.map((v, i) => ({ ...(r[i] || {}), [k]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This should do exactly what you want, assuming all arrays have equal length. With a bit of creativity this algorithm can be generalized to objects of arbitrary fields count. Here's the fiddle.
let initial = {
labels: [
'label1',
'label2',
'label3'
],
children: [
'child1',
'child2',
'child3'
],
numbers: [
1,
2,
3
]
};
function convertObjectToArray(
labels,
children,
numbers
) {
let final = [];
for (let i = 0; i < numbers.length; i++) {
final.push({
labels: labels[i],
children: children[i],
numbers: numbers[i],
});
}
return final;
}
console.log(convertObjectToArray(
initial.labels,
initial.children,
initial.numbers
));
I don't know of any built in javascript functions, but you can create a for loop (assuming that all arrays in the object are of same length):
for(let i = 0; i < initial[Object.keys(initial)[0]].length; i++){
FINAL_OUTPUT.push({
labels: initial.labels[i],
children: initial.children[i],
numbers: initial.numbers[i]
});
}
let initial = {
labels: ['label1', 'label2', 'label3'],
children: ['child1', 'child2', 'child3'],
numbers: [1 , 2 , 3]
};
let keys = Object.keys(initial);
let keyLength = keys[0].length;
let sampleValueArray = initial[keys[0]];
let i = 0;
let result = sampleValueArray.map( (item,index) => {
let temp = {};
keys.forEach( key =>
temp[key] = initial[key][index]
)
return temp
})
console.log(result)
let initial = {
labels: ['label1', 'label2', 'label3'],
children: ['child1', 'child2', 'child3'],
numbers: [1, 2, 3]
}
/* FINAL_OUTPUT = [
{ labels: 'label1', children: 'child1', numbers: 1 },
{ labels: 'label2', children: 'child2', numbers: 2 },
{ labels: 'label3', children: 'child3', numbers: 3 }
]; */
const result = Object.keys(initial).reduce((acc, x, i, keys) => {
const arr = keys.map((y, j) => initial[y][i]);
acc = [...acc, keys.reduce((acc_2, z, k) => ({
...acc_2,
[z]: arr[k]
}), [])]
return acc
}, [])
console.log(result)
let FINAL_OUTPUT =[]
for(let i =0;i<initial.length;i++){
FINAL_OUTPUT.push(
{labels: initial.labels[i],
children: initial.children[i],
numbers: initial.numbers[i]
})
}
You can use lodash's _.flow() to create a function that:
Uses to pairs to get an array of array of [key, [values]] pairs
Unzip to get separate keys from values
Destructure the keys and the values. Use _.unzip() to transpose the values, and then map, and use _.zipObject() with the keys to create the objects.
const { flow, toPairs, unzip, zipObject } = _;
const fn = flow(
toPairs, // convert to [key, values] pair
unzip, // transpose to array of keys, and array of values
([keys, values]) => // destructure keys and values
unzip(values) // transpose the values
.map(vals => zipObject(keys, vals)) // create object from keys and each set of values
);
const initial = {
labels: ['label1', 'label2', 'label3'],
children: ['child1', 'child2', 'child3'],
numbers: [1, 2, 3]
};
const result = fn(initial);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
I have an array of arrays
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
I'm trying to get the strings that appears in all arrays, which in this case only bar.
I tried a lot of things with .filter but all looks confusing.
Is there a simple solution find a string that appear in all arrays?
Edit:
What I have tried
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
const keySet = new Set()
arr.forEach(x => x.forEach(y => keySet.add(y)))
const uniqueKeys = Array.from(keySet)
console.log(uniqueKeys)
const res = uniqueKeys.filter(x => !arr.some(y => !y.includes(x)))
console.log(res)
You can do that in two steps:
Apply filter() on the first element of the array.(You can use an element)
Inside filter() use every() or the original array and check if that element is present in all the arrays.
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
const res = arr[0].filter(x => arr.every(a => a.includes(x)));
console.log(res)
You could reduce the arrays by filtering with a Set.
const
array = [['foo', 'bar', 'hey', 'oi'], ['foo', 'bar', 'hey'], ['foo', 'bar', 'anything'], ['bar', 'anything']],
common = array.reduce((a, b) => a.filter(Set.prototype.has, new Set(b)));
console.log(common);
you can use combination of reduce and filter to get the intersection between all arrays:
const res = arr.reduce((acc, a) => acc.filter(value => a.includes(value) ), arr[0])
If you use lodash, the code would be simpler though:
const _ = require('lodash');
const res = _.intersection(...arr);
This is the first solution I could come up with, see if it's ok for you:
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];
const result = [];
arr[0].forEach(str => {
let present = true;
arr.slice(1).forEach(array => {
if (!array.includes(str))
present = false;
});
if (present)
result.push(str);
});
Use .filter(), .flat() and .every().
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];
var flat = arr.flat();
//▼ filters through the words to see which ones are all included
console.log(flat.filter(v => arr.every(a => a.includes(v)))
.filter((v, i, a) => a.indexOf(v) === i));
//▲ filter through the 4 bars to get only one
Use .filter like :
const arr = [
str: {'foo', 'bar',
'hey', 'oi'},
str: {'foo', 'bar',
'hey'},
str: {'foo', 'bar',
'anything'},
str: {'bar',
'anything'}
]
const result = arr.filter((arr) => arr.str === bar)
console.log(result)
//gives you bar lines
I'm working with API data and I'm trying to build an object combining multiple arrays of data.
Current Arrays:
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar']
let arrX = ...
Desired Outcome:
let desiredOutcome = [
{
name: "John",
arr1: "bar", ...
},
{
name: "Jane",
arr1: "foo", ...
},
{
name: "Doe",
arr1: "foobar", ...
}]
I've been trying to play around with Object.assign() but I haven't had any luck:
var merge = Object.assign(obj, arr1 )
Is there a method or methods I could use?
Use .map() to add each element.
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar']
let result = name.map((a,i)=>{a.arr1 = arr1[i]; return a})
console.log(result)
You can do it using Array.map
Try the following:
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar'];
var result = name.map((o,i) =>Object.assign({"arr1" : arr1[i]},o));
console.log(result);
For an arbitrary count of arrays, you could take an array with the array of objects and the arrays of values and take short hand properties which preserves the name of the array and the values for adding to the result set with Object.assign.
var names = [{ name: "John" }, { name: "Jane" }, { name: "Doe" }],
arr1 = ['bar', 'foo', 'foobar'],
arrX = [1, 2, 3],
result = [names, { arr1 }, { arrX }]
.reduce((r, o) =>
(([k, a]) => a.map((v, i) => Object.assign({}, r[i], { [k]: v })))(Object.entries(o)[0])
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Maybe late but I'll provide some additional explanation on how to use .map:
The .map method creates a new array with the results of calling a provided function on every element in the calling array.
The method takes in one callback as argument. The callback itself can take predefined arguments. Here we will use the first two:
currentValue: e
index: i
Basically, the map method works by associating (literally mapping) each element of the looped array (here name) to the given returned value (here {name: e.name, arr1: arr1[i]}). Mapping is just a bijection between two arrays.
Another word on (e,i) => ({name: e.name, arr1: arr1[i]}):
It is the shorthand syntax called arrow function. It is similar to defining the callback function like so:
function(e,i) {
return { name: e.name, arr1: arr1[i] };
}
Full snippet will look like:
const name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
const arr1 = ['bar', 'foo', 'foobar']
const result = name.map((e,i) => ({ name: e.name, arr1: arr1[i] }))
console.log(result)
I have two arrays of same length
ids = [123, 456, 789, ...., 999];
names = ['foo', 'bar', ... , 'zzz'];
I want to create an array like
[ {id: 123, name: 'foo'}, {id: 123, name: 'bar'}, ..., {id: 999, name: 'zzz'} ]
I am trying to avoid forEach if possible.
Any suggestions?
Is map okay?
ids = [123, 456, 789, 999];
names = ['foo', 'bar', 'baz', 'zzz'];
result = ids.map(function(_, i) {
return {id: ids[i], name: names[i]}
});
console.log(result)
If you don't want to use any higher-order functions, then just do this:
var objects = [];
for (var i = 0; i < ids.length; i++) {
objects.push({id: ids[i], name: names[i]});
}
No need for forEach here. Use map which is similar to forEach.
var ids = [123, 456, 999];
var names = ['foo', 'bar', 'zzz'];
var result = ids.map(function (currentId, index) {
return {
id: currentId,
name: names[index]
};
});
console.log(result);
The forEach version would look like this (notice how similar they are):
var ids = [123, 456, 999];
var names = ['foo', 'bar', 'zzz'];
var result = [];
ids.forEach(function(currentId, index) {
result.push({
id: currentId,
name: names[index]
});
});
console.log(result);
The below code uses foreach but you dont need to handle it. I hope this will work for you.
ids = [123, 456, 789, 999];
names = ['foo', 'bar', 'zab', 'zzz'];
result = ids.map(function(_, i) {
return {id: ids[i], name: names[i]}
});
console.log(result)
I have a couple of arrays that look like the following:
var foo = ['id', 'first', 'last'];
var student1 = ['1', 'sam', 'smith'];
var student2 = ['2', 'jon', 'murphy'];
Is there an efficient tool, perhaps using a library like underscore.js or vanilla javascript that will allow you to turn those three arrays into an object that looks like the following:
var finalObj = [
{'id' => 1, 'first' => 'sam', 'last' => 'smith'},
{'id' => 2, 'first' => 'jon', 'last' => 'murphy'}
];
A solution in plain Javascript
var foo = ['id', 'first', 'last'],
student1 = ['1', 'sam', 'smith'],
student2 = ['2', 'jon', 'murphy'],
result = [student1, student2].map(function (a) {
var o = {};
foo.forEach(function (k, i) {
o[k] = a[i];
});
return o;
});
console.log(result);
ES6 with Array#reduce
var keys = ['id', 'first', 'last'],
st1 = ['1', 'sam', 'smith'],
st2 = ['2', 'jon', 'murphy'],
result = [st1, st2].map(a => keys.reduce((o, k, i) => (o[k] = a[i], o), {}));
console.log(result);
Assuming that the order of the arrays always matters (it will always be ID, First, Last) - you could do something like:
var people = [student1, student2]; //create 2d array
var finalObj = people.reduce(function(final, person) {
var obj = {};
obj[foo[0]] = person[0]
obj[foo[1]] = person[1]
obj[foo[2]] = person[2]
final.push(obj);
return final;
}, []);
//[Objectfirst: "sam"id: "1"last: "smith"__proto__: Object, Objectfirst: "jon"id: "2"last: "murphy"__proto__: Object]
Underscore can help, for example:
_.map( [student1, student2], function(arr) {
return _.object(foo, arr);
})