I'd love an explanation as to why the result of this function don't match my expectation.
const numbers = [ 1, 2 ]
const objects = [{f: 'a'}, {f: 'b'}]
async function(domain) {
let matrix = []
objects.forEach((object) => {
numbers.forEach((number) => {
object.number = number
matrix.push(object)
})
})
return matrix
}()
Actual
The result, once the promise is resolved returns:
[
{ f: 'a', number: 2 },
{ f: 'a', number: 2 },
{ f: 'b', number: 2 },
{ f: 'b', number: 2 }
]
Expected
But, my expectation is that it would return:
[
{ f: 'a', number: 1 },
{ f: 'a', number: 2 },
{ f: 'b', number: 1 },
{ f: 'b', number: 2 }
]
One of the things that puzzles me the most is that if I console.log the value of object just before I push, it logs out each of the objects in my expected result.
Because objects are passed by reference and you are modifying original object, instead you can push new object.
const numbers = [ 1, 2 ]
const objects = [{f: 'a'}, {f: 'b'}]
let matrix = []
objects.forEach((object) => {
numbers.forEach((number) => {
matrix.push({...object, number})
})
})
console.log(matrix)
Use Array.flatMap() to iterate the objects, with a nested Array.map() to iterate the numbers and return an array of new objects with the relevant number. The flatMap will flatten the arrays produced by the map to a single array:
const numbers = [ 1, 2 ]
const objects = [{f: 'a'}, {f: 'b'}]
const matrix = objects.flatMap(o => // map the objects and flatten
numbers.map( // map the numbers
number => ({ ...o, number }) // return a new object with the number
)
);
console.log(matrix);
Old answer:
Use nested Array#map to iterate the objects and the numbers, and Object#assign to create new objects that include the relevant number. Flatten resulting nested arrays by using the spread syntax in Array#concat:
const numbers = [ 1, 2 ]
const objects = [{f: 'a'}, {f: 'b'}]
const matrix = [].concat(... // flatten the nested arrays
objects.map((o) => // map the objects
numbers.map( // map the numbers
(number) => Object.assign({}, o, { number }) // return a new object with the number
)
));
console.log(matrix);
#Nenad is correct. You can also do it with reduce and map.
const numbers = [ 1, 2 ];
const objects = [{f: 'a'}, {f: 'b'}];
const matrix = numbers.reduce((acc, nxt) => {
const numberedObjs = objects.map(obj => ({...obj, number:nxt}));
acc.push(...numberedObjs);
return acc;
}, []);
Related
for example - lets say I have the array -
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
I want to run once on that array and at the end of that run to have two arrays -
const arrayOne = ["first", "second"];
const arrayTwo = [1,2];
to get the first one is easy, but getting both at once?
I remember there was a way to do it but couldn't find it..
I'd appreciate any help!
Any looping logic will help
Array.reduce implementation will be like below
const array = [{ name: "first", val: 1 }, { name: "second", val: 2 }];
const [arrayOne, arrayTwo] = array.reduce((acc, curr) => {
const { name, val } = curr;
acc[0].push(name);
acc[1].push(val);
return acc;
}, [[], []]);
console.log(arrayOne, arrayTwo);
The function extractArrays is general-purpose and can be used in other cases as well.
function extractArrays(arr) {
const result = {};
for (obj of arr) {
for (key in obj) {
result[key] = (result[key] || []).concat([obj[key]]);
}
}
return result;
}
const array = [{name: "first", val: 1}, {name: "second", val: 2}];
const result = extractArrays(array);
const arrayOne = result.name;
const arrayTwo = result.val;
console.log(`arrayOne=${arrayOne}`);
console.log(`arrayTwo=${arrayTwo}`);
You can use Array.reduce to achieve this:
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
const result = array.reduce((res, item) => {
res[0].push(item.name)
res[1].push(item.val)
return res
}, [[], []])
console.log(result)
thanks everyone!
but I think that the easiest, most readable code would be something like -
const itemArray = [], valArray = [];
data.map(({name, val})=> {
if(name) nameArray.push(name);
if(val) valArray.push(val);
})
because basically in 4 lines of code it's finished
thanks again everyone!
const array = [{name: "first", val: 1}, {name: "second", val: 2}]
const keys = [];
const values = [];
array.forEach(item=>{
keys.push(item.name);
values.push(item.val);
})
console.log(keys, values)
Use the Array.map function:
const array = [ { name: 'first', val: 1 }, { name: 'second', val: 2 } ]
let names = array.map(item => item.name)
let vals = array.map(item => item.val)
console.log(names)
console.log(vals)
The map function calls a callback function you provide on each element and constructs a new array from the results of that function.
If you are not familiar with arrow functions like:
item => item.name
... it is a short form for:
function (item) {
return item.name
}
You could even do it in one line:
let [ names, vals ] = [ array.map(item => item.name), array.map(item => item.val) ]
I want to create an object with the given structure:
const questions = [
{
id: '1',
instruction: 'Question1',
options: {
'a': 'SomeText1',
'b': 'SomeText2',
'c': 'SomeText3'
},
correct: ['c']
},
{
id: '2',
instruction: 'Question2',
options: {
'a': 'SomeText1',
'b': 'SomeText2',
'c': 'SomeText3',
'd': 'SomeText4'
},
correct: ['a']
},
{
id: '3',
instruction: 'Question3,
options: {
'a': 'SomeText1',
'b': 'SomeText2'
},
correct: ['b']
}
]
I have an arrays containing necessary information to fill this object and create it using .map() .
const questions =
[ 'Question1',
'Question2',
'Question3'
]
const answers =
[
'Answer1',
'Answer2',
'Answer3'
]
const options = [
[ 'Option1', 'Option2', 'Option3' ],
[ 'Option4', 'Option5', 'Option6' ],
[ 'Option7', 'Option8', 'Option9' ]
]
function toJson()
const alphabet = ['a', 'b', 'c', 'd', 'e'];
const json = questions.map((question, index) => (
{
id: index + 1,
instruction: question,
options: Object.assign({}, options[index]),
correct: answers[index]
}
))
}
I have only problem with options key. As You see I want to have a letters as keys, depending on how many answers question has.
This function gives me numbers as keys when I use Object.assign(), and I don't know how to replace them with letters from alphabet array.
EDIT:
So the solution for the options key in desired object is:
options: Object.assign(
{},
...options[index].map((a, i) => ({ [alphabet[i]]: a }))
),
Now I'm able to create an object with consecutive alphabet letters with assigned answer.
options[index] returns an array. It contains values by index. By passing it to Object.assign, you add all values by their array index as a string: "0", "1", etc.
If we map the array in to a list of { "a": option } first, and spread the result in to the Object.assign call, we can change those indexes to the letters you want:
const questions =
[ 'Question1',
'Question2',
'Question3'
]
const answers =
[
'Answer1',
'Answer2',
'Answer3'
]
const options = [
[ 'Option1', 'Option2', 'Option3' ],
[ 'Option4', 'Option5', 'Option6' ],
[ 'Option7', 'Option8', 'Option9' ]
]
function toJson() {
const alphabet = ['a', 'b', 'c', 'd', 'e'];
const json = questions.map((question, index) => (
{
id: index + 1,
instruction: question,
options: Object.assign(
{},
...options[index].map((a, i) => ({ [alphabet[i]]: a }))
),
correct: answers[index]
}
));
return json;
}
console.log(toJson());
I suggest using something like zip and objectFromPairs (both snippets from 30secondsofcode, a project/website I am a maintainer of). From the website:
zip
Creates an array of elements, grouped based on the position in the original arrays.
Use Math.max.apply() to get the longest array in the arguments. Creates an array with that length as return value and use Array.from() with a map-function to create an array of grouped elements. If lengths of the argument-arrays vary, undefined is used where no value could be found.
objectFromPairs
Creates an object from the given key-value pairs.
Use Array.reduce() to create and combine key-value pairs.
The only extra step I took was to trim each zipped array to the length of options[index].
const questions = ['Question1',
'Question2',
'Question3'
]
const answers = [
'Answer1',
'Answer2',
'Answer3'
]
const options = [
['Option1', 'Option2', 'Option3'],
['Option4', 'Option5', 'Option6'],
['Option7', 'Option8', 'Option9']
]
const zip = (...arrays) => {
const maxLength = Math.max(...arrays.map(x => x.length));
return Array.from({
length: maxLength
}).map((_, i) => {
return Array.from({
length: arrays.length
}, (_, k) => arrays[k][i]);
});
};
const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {});
function toJson() {
const alphabet = ['a', 'b', 'c', 'd', 'e'];
const json = questions.map((question, index) => ({
id: index + 1,
instruction: question,
options: objectFromPairs(zip(alphabet, options[index]).slice(0, options[index].length)),
correct: answers[index]
}))
console.log(json);
}
toJson();
the below should work (i believe)
options: alphabet.reduce((acc, letter, i) => {
let option = options[index][i] || 'DefaultText' + i;
acc[letter] = option;
return acc;
}, {})
Edit: Corrected typos
EDIT:
So the solution for the options key in desired object is:
options: Object.assign(
{},
...options[index].map((a, i) => ({ [alphabet[i]]: a }))
),
I'm new to node js/express. I'm having the problem cause I need to insert bulk in MySQL. I use body-parser, but to simplify my code this is the analogy.
I have two objects from req.body:
Numbers = { 1, 2, 3 }
Letters = { a, b, c }
Then, I need it to be like this,
Object = [ { '1', 'a' }, { '2', 'b' }, { '3', 'c' } ]
What can I use to do this?
const Numbers = [1, 2, 3]
const Letters = ['a', 'b', 'c']
const result = []
Numbers.forEach((el, i) => {
result.push({[el]: Letters[i]})
})
console.log(result)
or
const Numbers = [1, 2, 3]
const Letters = ['a', 'b', 'c']
const result = Numbers.map((el, i) => ({[el]: Letters[i]}))
console.log(result)
I have an array like this:
var array = ['test1', 'test2', 'test3', 'test4']
I would like to make a new object from this array, and they should have the same keys. Desired outcome should be like this:
var objectFromArray = [
{ responsibilityName: "test1" },
{ responsibilityName: "test2" },
{ responsibilityName: "test3" },
{ responsibilityName: "test4"}
]
How is this possible in js?
Adjusted to your comment: you can use reduce and map to flatten the arrays within the array of objects.
[Edit based on your comment]
const arr = [
{ responsabilityName: ['test1', 'test2', 'test3', 'test4'],
somethingElse: [1, 2, 3, 4] } ];
const arrMapped = arr
.reduce( (mappedArr, obj) =>
Object.keys(obj)
.map( key => obj[key].map( prop => ({ [key]: prop }) ) )
.reduce( (p, n) => p.concat(n), [] ),
[] );
console.log(arrMapped);
Iterate over the array, create objects in the other one. As simple as that.
var array = ['test1', 'test2', 'test3', 'test4']
var objectFromArray = []
array.forEach((v)=>{objectFromArray.push({"responsibilityname":v})})
use array.map and assign the value to the object
DEMO
var array = ['test1', 'test2', 'test3', 'test4'];
var result = array.map(function(el) {
var obj = {};
obj['responsibilityname'] = el;
return obj;
})
console.log(array);
console.log(result);
Loop over the array and return a new object using map or forEach etc.
var array = ['test1', 'test2', 'test3', 'test4']
var arr = array.map(value => {
return {responsibilityName: value};
})
console.log(arr);
I have an array as follows:
const arr = [{
name: 'XYZ',
values: [1, 2, 3]
}, {
name: 'ABC',
values: [5]
}, {
name: 'XYZ',
values: [4, 5, 6]
}, {
name: 'ABC',
values: [8, 9]
}];
I'm using underscore js and trying to transform as follows:
const result = [{
name: 'XYZ',
values: [1, 2, 3, 4, 5, 6]
}, {
name: 'ABC',
values: [5, 8, 9]
}]
I was able to group by name and trying to loop in, but not sure how do I merge values. So far this is what I've done:
_.chain(arr)
.groupBy((item) => item.name)
// I don't know what to do here
.value();
With ES6, you can use Array#reduce with a Map to get the desired result:
const arr = [{"name":"XYZ","values":[1,2,3]},{"name":"ABC","values":[5]},{"name":"XYZ","values":[4,5,6]},{"name":"ABC","values":[8,9]}];
const result = [...arr.reduce((m, { name, values }) => {
const el = m.get(name) || { name, values: [] }; // get the result object from the map or create a new one
el.values.push(...values); // push the current values to the result object values property
return m.set(name, el); // add the result object to the map, and return the map
}, new Map()).values()]; // get the map values, and spread to an array
console.log(result);
Using underscore:
const arr = [{"name":"XYZ","values":[1,2,3]},{"name":"ABC","values":[5]},{"name":"XYZ","values":[4,5,6]},{"name":"ABC","values":[8,9]}];
const result = _.chain(arr)
.groupBy('name') // group by name
.mapObject((group, name) => ({ // map each group to a new object
name,
values: _.flatten(_.pluck(group, 'values')) // get all values arrays, and flatten to a single array
}))
.values() // convert the groups object to an array
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Maybe, you can try vanilla Javascript way.
var result = [];
arr.forEach((item) => {
let currObj = result.find((item2) => item2.name === item.name);
if(currObj){
currObj.values = currObj.values.concat(item.values);
} else {
result.push(JSON.parse(JSON.stringify(item)));
}
})