How to get a particular attribute from an array of array objects? - javascript

I have an Array of Arrays, and each Array consists of objects. Here is a simplified version of what I'm referring to (it is a console.log of my original array) -
Array - [Array(2), Array(3), Array(2)]
Each Array has objects in the following format (taking the first array from above) -
Array(2) -
0: {name: "test", score:40, date: "2018-09-18T00:00:00.000Z"}
1: {name: "test2", score:50 date: "2018-09-18T00:00:00.000Z"}
The other arrays are similar with the same attributes and different values.
I am trying to fetch the name attribute from each of these objects. I tried the below code - but I end up getting an undefined value:
const test1= array1.map(x=> x.values) // this gives me the array of arrays
const test2 = test1.map(function(y){return y.name})// this is my attempt to get the 'name' attribute from all of the arrays that include the objects.
What am I missing out on here? Is there a better way to get the attribute using arrow functions?

Flatten it, and map it to names or Vise versa
First flatten it, and map
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = [].concat(...array).map(({name})=>name);
console.log(res);
Now, map it to names and then flatten
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = [].concat(...array.map(a=>a.map(b=>b.name)))
console.log(res);
Now, In this one, certainly you can notice that we are actually mapping it in each level (we have to, no other way with first map only approach. so we can perform a reduce in place of the outer map and concat it there itself, so we can avoid the outer concat (for flatten) and inner concat will actually flatten it. Here we go:
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.reduce((r, a)=>r.concat(a.map(b=>b.name)), []);
console.log(res);

/* TEST DATA */
array1 = [
{ name: 'test1', score: 40, date: '2018-09-18T00:00:00.000Z' },
];
array2 = [
{ name: 'test4', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test5', score: 40, date: '2018-09-18T00:00:00.000Z' },
];
array3 = [
{ name: 'test6', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test7', score: 50, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test8', score: 40, date: '2018-09-18T00:00:00.000Z' },
{ name: 'test9', score: 50, date: '2018-09-18T00:00:00.000Z' },
];
testResults = [array1, array2, array3];
// Solution
function getListOfName(){
let names = [];
testResults.map(testResult => {
testResult.map(({name}) => {if(name) names.push(name)})
})
return names;
}
console.log("Full list of names", getListOfName());
// If you want to restrict to K names from each array
function getFirstKNamesfromArray(limit){
let names = [];
testResults.map(testResult => {
testResult.map(({name}, index) => {
if(name && (index < limit)) names.push(name)
})
})
return names
}
console.log("First 2 names from each array", getFirstKNamesfromArray(2));

Take into account that map returns an array; you iterate over it. Filter or reduce do the same.
const test1= array1.map(x=> x.values) // x doesn't have a property named "value"
//simply use forEach
array1.forEach((el) => console.log(el.name))
If you want to capture the names inside a collection:
const let container = [];
array1.forEach((el) => container.push(el.name))
A good way to better understand this iterator functions would be to first use loops and then attempt to "translate" your code into one of them.

Because in your first map x is an array, not an object. So, there is no value. You should map inner arrays then get the desired value.
const arr = [
[
{
name: "test",
score: 40,
date: "2018-09-18T00:00:00.000Z"
},
{ name: "test2", score: 50, date: "2018-09-18T00:00:00.000Z" }
],
[
{
name: "foo",
score: 40,
date: "2018-09-18T00:00:00.000Z"
},
{ name: "bar", score: 50, date: "2018-09-18T00:00:00.000Z" }
]
];
const test1 = arr
.map(x => x.map(y => y.name))
.reduce((acc, el) => [...acc, ...el], []);
console.log(test1);

This should work fine. You need to flatten the array structure and map the names.
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
const names = array.reduce((acc, innerArray) => {
return [...acc, ...innerArray.map(entry => entry.name)]
}, [])
console.log(names)

Here:
const arr = [
[{name: 'a', date:'x'}, {name: 'b', date:'y'}],
[{name: 'c', date:'x'}, {name: 'd', date:'y'}]
];
const names = arr.map(el => el.map(obj => obj.name));
console.log(names.join());
console.log(names.flat());
you can use flat() to keep names in an array or join() to merge the names into a string.

const test1= array1.map(x=> x.values)
This is returning undefined.
let requiredArr = [];
let array1 = [Array(2), Array(3), Array(2)]
let test2 = array1.map(x => x.map(y => requiredArr(y.name));
test2 will give the desired result.

Adding to Koushik's example, with ES2019, you can use flat() to flatten nested arrays:
const array = [[{name: 'test1'}, {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.flat().map( ({name}) => name );
console.log(res);
Or if you have deeper levels:
const array = [[[{name: 'test1'}], {name: 'test2'}], [{name: 'test3'}, {name: 'test4'}]]
var res = array.flat(2).map( ({name}) => name );
console.log(res);
And so on.

Related

Compare one array with a nested array and push value into a new array with same index in Javascript

I have 2 arrays
const arrayOne = [
{id: '110'},
{id: '202'},
{id: '259'}
];
const arrayTwo = [
{data: [{value: 'Alpha', id: '001'}]},
{data: [{value: 'Bravo', id: '202'}]},
{data: [{value: 'Charlie', id: '110'}]},
{data: [{value: 'Delta', id: '202'}]}
];
I need to create a new array comparing arrayOne[idx].id with arrayTwo[idx].data[idx2].id
Upon match, I need to create an array pushing value (arrayTwo[idx].data[idx2].value) to the new array against each index in arrayOne.
In this example, I would get newArray = [null, 'Bravo', null, Delta]
What I have tried:
arrayOne.map(item => ({
...item,
result: arrayTwo.filter(itemTwo => item.data.map(x => x.id).includes(itemTwo.id))
}));
and also
const newArr = [];
arrayOne.map((item, idx) => {
if (arrayTwo.filter(itemTwo => itemTwo.data?.map(x => x.id) === item.id)) {
newArr.push(arrayTwo.data[idx].value);
} else newArr.push(null);
});
To do this you can map arrayTwo and use .find() to search for the ID in arrayOne. I also mapped arrayTwo to the inner object to make the second map more concise.
const arrayOne = [
{id: '110'},
{id: '202'},
{id: '259'}
];
const arrayTwo = [
{data: [{value: 'Alpha',id: '001'}]},
{data: [{value: 'Bravo',id: '202'}]},
{data: [{value: 'Charlie',id: '777'}]},
{data: [{value: 'Delta',id: '202'}]}
];
const result = arrayTwo
.map(obj => obj.data[0])
.map(obj => (arrayOne.find(v => v.id === obj.id) && obj.value) || null)
console.log(result)
Use map to iterate over each element of arr1 and return a new array.
Reassemble the data attribute array of each element in the arr2 array
using map and flat
When arr1 traverses, you can get the current element id, use filter
to filter the combined data array, and return an element array that matches
the current element id.
Based on the case where the id is not matched, use the optional chain operator to get the value.
When returning
if you want to get the element array of the id and
value attributes, use conditional (ternary) operator, when it doesn't match, return the original element,
when it matches, use spread syntax, copy the current element
attribute, and add the value attribute
if you only want to get an
array of matching results, just return the value,
remember to use the optional chain operator to convert the unmatched
value to null.
const arr1 = [
{ id: '110' },
{ id: '202' },
{ id: '259' }
];
const arr2 = [
{ data: [{ value: 'Alpha', id: '001' }] },
{ data: [{ value: 'Bravo', id: '202' }] }
];
const result1 = arr1.map(o1 => {
const data = arr2.map(o2 => o2.data).flat();
const value = data.filter(o2 => o2.id === o1.id)[0]?.value;
return value ? {...o1, value} : o1;
});
const result2 = arr1.map(o1 => {
const data = arr2.map(o2 => o2.data).flat();
const value = data.filter(o2 => o2.id === o1.id)[0]?.value;
return value ?? null;
});
[result1, result2].forEach(r => console.log(JSON.stringify(r)));
You can try this easy line of code :
const arrayOne = [{ id: '110' }, { id: '202' }, { id: '259' }];
const arrayTwo = [{ data: [{ value: 'Alpha', id: '001' }], }, { data: [{ value: 'Bravo', id: '202' }] }];
let result = arrayOne.map(el => {
let found = arrayTwo.find(f => f.data.at(0)?.id == el.id)?.data.at(0)?.value;
return { id: el.id, value: found ?? null};
});
console.log(result);

Unable to use array on reduce

Const people = [ { name: 'siddiq', age: 20} , { name: 'anas', age: 19}]
Const arr = people.reduce((acc, curr) => acc.push(curr.age), [])
It is not working. What i want is to creare an array with only ages...??
You should use map() instead:
const people = [ { name: 'siddiq', age: 20} , { name: 'anas', age: 19}]
const arr = people.map(p => p.age)
//[20, 19]
reduce() requires that you return the accumulator from the callback function (since the accumulator might not be a mutable object). push() returns the length of the updated array, so the second iteration tries to do (1).push(curr.age, []), which doesn't work.
The comma operator is useful for this in arrow functions.
Also, there's no reason to push [] onto acc.
const people = [ { name: 'siddiq', age: 20} , { name: 'anas', age: 19}]
const arr = people.reduce((acc, curr) => (acc.push(curr.age), acc), []);
console.log(arr);
Another option is to use the spread syntax to ensure you'll return an array within reduce method in a cleaner and modern way.
const people = [ { name: 'siddiq', age: 20} , { name: 'anas', age: 19}]
const arr = people.reduce((acc, curr) => [...acc, curr.age], []);
console.log(arr);

JavaScript: How to add and sort the same fields in an array based on fields?

I have the following array a as shown below:
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
I want to filter by array name and add their own num
var currentName = a[0]
let newArrys=[]
for(let i = 0; i<a.length;i++){
if(currentName.name == a[i].name){
a[i].num = a[i].num + currentName.num
let tmepArry = [];
tempArry.push(a[i]);
newArrys.push(tempArry);
}
}
I am trying to obtain the following 2D array:
[
[{name: 'phone', id:1, num:4}],
[{name: 'milk',id:2, num:1}],
[{name: 'apple', id: 3 num:1}]
]
The result cannot be screened out.
My attempt is invalid.
Can you help me?
Given:
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
const newArrys = a.reduce((acc, current) => {
// find an object in the array with a matching name
const existing = acc.find(obj => obj.name === current.name);
if (existing) {
// combine the numbers
existing.num += current.num;
} else {
acc.push(current);
}
return acc;
}, []).map(obj => [obj])
That will get you what you need.
Here's a quick example of how to go about it. Essentially it's a two step process that involves first reducing your array of objects into a distinct list with the counts (num). Then, iterating over your results to create your 2D array.
There's probably a fancier way to produce the same result by adding a little bit more code to the reducer, but trying to go for readability here as it's rather easy to get lost in reduce functions.
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
// Get the counts using reduce
const results = a.reduce( (acc, curr) => {
if (acc.hasOwnProperty(curr.name)) {
acc[curr.name].num += curr.num;
} else {
acc[curr.name] = {id: curr.id, num: curr.num };
}
return acc;
}, {});
// Establish result array
const finalResult = [];
// Iterate over results object and format them into an array of a single object
// then push the array to the finalResult array (thus making it 2D)
for (const key in results) {
const item = results[key];
finalResult.push([{ name: key, id: item.id, num: item.num }]);
}
console.log(finalResult);
Not sure if this is the best solution but it does work. Please feel free to give advise on what I should have done instead for a better code. Haha..
var a = [
{name: 'phone' , id:1 ,num:1},
{name: 'milk' ,id:2, num:1},
{name: 'apple' , id:3 , num:1},
{name: 'phone', id: 4, num:3},
]
function organize_array(tmpArray) {
let data = []
tmpArray.forEach(function(value, key) {
if(data.filter(tmp => tmp.name == value.name) == '') {
const tmpFiltered = a.filter(tmp => tmp.name == value.name)
let total = 0
tmpFiltered.map(x => { total += x.num })
data.push({name: value.name, num: total})
}
})
return data
}
console.log(organize_array(a))

Creating a key:value object from a flat object

I'm using Javascript to get data from an API.
I get the following list of objects.
[
{name: 'Cat', value: 2, extra: 'data'},
{name: 'Dog', value: 3, extra: 'data'}
]
I'm trying to get to the following form
[
cat: {value: 2},
dog: {value: 3}
]
I'm currently trying using map but I don't see where the key part comes in.
return data.map((item) => ({
value: item.value
}));
var data = [
{name: 'Cat', value1: 2, value2: 3},
{name: 'Dog', value1: 3, value2: 4}
]
var result = data.map((item) => {
var name = item.name
delete item.name
//if you want to modify some property
item.value1 = item.value1 + "$"
return {[name]: {...item}}
})
console.log(result)
const result = {};
for(const {name, value} of array)
result[name] = { value };
A plain old for loop does it. With functional programming you would have to use reduce to boil it down to one single object, map always returns an array.
const result = array.reduce((res, {name, value}) => ({ ...res, [name]: {value}}), {});
You can use Object.assign() with map() method to return object as a result.
const data = [{name: 'Cat', value: 2},{name: 'Dog', value: 3}]
const result = Object.assign({}, ...data.map(({name, value}) => ({[name]: {value}})))
console.log(result)

Assign First Element of Nested Array as Property of Parent Object

Assuming the following Array:
[
{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]},
]
I want to promote sources[0] to a property value, either under sources itself or as a new key using lodash.
I've done the following:
myList = _.map(monitorList, _.partialRight(_.pick, ['id', 'name', 'sources']));
mySources = _.map(monitorList, 'sources');
I imagine I can iterate through each respective array now and map my index from mySources to the sources key in myList, however it seems like there should be a functional way using lodash to promote a nested array item to a property value.
Ideal final data structure:
[
{id: 1234, name: "#Acme", sources:"Twitter"},
{id: 5678, name: "#Enron", sources:"Facebook"},
]
With a functional ES6 approach:
const monitorList = [
{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]},
];
var result = monitorList.map(o => Object.assign({}, o, { sources: o.sources[0] }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can follow a simple path and use forEach to replace sources property:
var items = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
items.forEach((item) => item.sources = item.sources[0]);
console.log(items);
Another solution, using map, which is more functional (as it does not change items variable):
var items = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
var newItems = items.map((item) => Object.assign({}, item, { sources: item.sources[0] }));
console.log(newItems);
You could use map:
var array = [{id: 1234, name: "#Acme", sources:["Twitter"]},
{id: 5678, name: "#Enron", sources:["Facebook"]}];
var items = array.map(item => {
item.source = item.sources[0];
return item;
});
You could change item.source to item.sources as well if you wanted to overwrite.
Another way using some losdash methods:
var items = array.map(item => {
return _.assign({}, item, {sources: _.first(item.sources)});
});

Categories

Resources