I have an array of objects like this:
let list = [
{
'items': [
'item 1',
'item 2'
]
},
{
'items': [
'item 3'
]
}
]
and I want flatten the arrays from this object like this:
['item 1','item 2','item 3']
Which JavaScript function should I use for this output?
I have tried with the map function:
list.map(i => i.items)
but I got this output:
[["item 1","item 2"],["item 3"]]
NOTE : I am looking for any existing function or an answer that is wrapped in a function so I can just call a function - not write the loop out myself.
You can flat the map() result using Array.prototype.flatMap():
The flatMap() method first maps each element using a mapping function, then flattens the result into a new array.
let list = [
{
'items': [
'item 1',
'item 2'
]
},
{
'items': [
'item 3'
]
}
]
list = list.flatMap(i => i.items);
console.log(list);
You could use reduce(). There is no way to avoid looping since Array prototype methods do loops internally
let list = [
{
'items': [
'item 1',
'item 2'
]
},
{
'items': [
'item 3'
]
}
];
const res = list.reduce((a,c) => [...a, ...c.items],[])
console.log(res)
There are multiple ways you can achieve this:
const list = [{'items': ['item 1','item 2']},{'items': ['item 3']}]
// Using map and flat
console.log(list.map(o => o.items).flat())
// Using flatMap
console.log(list.flatMap(o => o.items))
// Using reduce
console.log(list.reduce((a, o) => a.concat(o.items), []))
// Using a plain old for loop (wrapped in a function)
const getItems = list => {
let temp = []
for (let i = 0; i < list.length; i++) {
const items = list[i].items
for (let j = 0; j < items.length; j++) {
temp.push(items[j])
}
}
return temp
}
console.log(getItems(list))
However, if you want a performance-first solution, reduce + for loop is the way to go:
const list = [{'items': ['item 1','item 2']},{'items': ['item 3']}]
console.log(list.reduce((a, o) => {
for (var i = 0; i < o.items.length; i++) a.push(o.items[i])
return a
}, []))
Check this jsperf for test cases.
you can use the Array.reduce method and follow the docs here
{
let list = [
{
'items': [
'item 1',
'item 2'
]
},
{
'items': [
'item 3'
]
}
];
/**
* #parameter {Array} arg
*/
function splat (arg) {
return arg.reduce((total, { items }) => [...total, ...items], []);
}
console.log(splat(list));
}
You could also play with recursive function to make a more generic function that accepts array of nested objects.
https://lodash.com/docs/4.17.14#flatten
And
https://lodash.com/docs/4.17.14#flattenDeep
Look like they're exactly what you need.
Related
Assume there is a nested array like this:
[
[ 'one', 'third ],
[ 'one', 'second', 'fourth' ],
[ 'one', 'third' ],
]
I need to make the values unique by order priority: If an element is existing in the first array, it should be removed from the second and third. An element of the second array should not exist in the third.
So the result should be:
[
[ 'one', 'third ],
[ 'second', 'fourth' ],
[],
]
I would iterate over each array and each element, but this removes an element only from the next array (which is missing the last array or errors if the loop is at the last array) and it feels very hacky...
for (let i = 0; i < array.length; i++) {
const element = array[i];
for (let j = 0; j < element.length; j++) {
const string = element[j];
const index = array[i + 1].indexOf(string)
if (index !== -1) {
array[i + 1].splice(index, 1)
}
}
}
You could take a Set and filter the values with a lookup and adding the value, if not seen.
const
values = new Set,
data = [['one', 'third'], ['one', 'second', 'fourth'], ['one', 'third']],
result = data.map(a => a.filter(v => !values.has(v) && values.add(v)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It doesn't get much simpler than what you have done. Here is an alternative approach using a nested .forEach() and a hash u to keep track of already encountered array elements:
const arr=[
[ 'one', 'third' ],
[ 'one', 'second', 'fourth' ],
[ 'one', 'third' ],
];
const res=[], u={};
arr.forEach(r=>{
res.push([]);
r.forEach((c,i)=>{
u[c] || (u[c]=res[res.length-1].push(c))
})});
console.log(res);
This can be done via a two step process:
Use Set on each sub-array to remove any duplicate elements
Use .filter() and .some() methods to iterate through each element of each sub-array and leave out (filter) any that are in any lower-index sub-array. The first sub-array - index 0 - is returned whole as there are no lower-index sub-arrays to compare with.
const data = [[ 'one', 'third'],[ 'one','second','fourth'], ['one', 'third']];
const result = data.map(arr => [...new Set(arr)]).map(
(arr,i,a) => i === 0 ? arr : arr.filter(
v => !a.slice(0,i).some(x => x.includes(v))
)
);
console.log( result );
An immutable approach, using reduce() and flat():
const data = [[ 'one', 'third' ], [ 'one', 'second', 'fourth' ],[ 'one', 'third' ]];
const result = data.reduce((acc, val) => [
...acc,
val.filter(item => !acc.flat().includes(item))
], []);
console.log(result);
Hello there good Samaritan, i would like to use Lodash and find the user with most books in the array.
const books = [ {id:0, name: 'Adam', title: 'xx'}, {id:1, name:'Jack', title:'yy'}, { id: 2, name: 'Adam',title:'zz' } ]
Thanks in advance :)
function search_book(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].book === nameKey) {
return myArray[i];
}
}
}
var array = [
{ book:"deep learning", value:"this", other: "that" },
{ book:"ml", value:"this", other: "that" }
];
var resultObject = search_book("ml", array);
console.log(resultObject)
_.filter(list, { name: 'Adam' })
var group = _.countBy(list, function(item){return item.name});
That will get the counts of author in the list, then you can sort and find the one with the largest.
You can generate a function with lodash's _.flow():
Count the objects by the name property
Convert the resulting object of the previous step to [key, value] pairs,
Find the pair with the max value
Get the key (the name)
const { flow, countBy, toPairs, maxBy, tail, head } = _
const fn = flow(
arr => countBy(arr, 'name'), // count by name
toPairs, // convert to [key, value] pairs
arr => maxBy(arr, tail), // find the max by the value (tail)
head // get the key (head)
)
const books = [ {id:0, name: 'Adam', title: 'xx'}, {id:1, name:'Jack', title:'yy'}, { id: 2, name: 'Adam',title:'zz' } ]
const result = fn(books)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
And the same idea using Lodash/fp:
const { flow, countBy, toPairs, maxBy, tail, head } = _
const fn = flow(
countBy('name'), // count by name
toPairs, // convert to [key, value] pairs
maxBy(tail), // find the max by the value (tail)
head // get the key (head)
)
const books = [ {id:0, name: 'Adam', title: 'xx'}, {id:1, name:'Jack', title:'yy'}, { id: 2, name: 'Adam',title:'zz' } ]
const result = fn(books)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
I have an array of objects that looks like this.
var items = [
{id: 1150, title: 'im tyler'},
{id: 1195, title: 'im josh'}
];
And another array that looks like this:
var sortArray = [
'1195',
'1150'
];
What i am trying to accomplish is a sorting based on result from the sort array. So in this scenario that items array should sort the object with id = 1195 as first in the list. Also if there is only one id in the sortArray it should only display that object in the items array.
Wanted result:
var Newitems = [
{id: 1195, title: 'im josh'}
{id: 1150, title: 'im tyler'},
];
You can loop over the sort array, and in each iteration find the element in the source array. If found, push the result to a new array.
Though it generates a new array, please note that the items still refer to the original array. The new array just contains the references to original items.
var sortArray = [
'1195',
'1150'
];
var items = [
{id: 1150, title: 'im tyler'},
{id: 1195, title: 'im josh'}
];
var res = [];
sortArray.forEach(item => {
res.push(items.find(i => i.id.toString() === item));
});
console.log(res);
You could create an object from sort array and then use that object to sort.
var items = [{id: 1150, title: 'im tyler'},{id: 1195, title: 'im josh'}];
var sortArray = ['1195','1150'].reduce((r, e, i) => Object.assign(r, {[e]: i}), {})
items.sort((a, b) => sortArray[a.id] - sortArray[b.id]);
console.log(items)
It looks like, you need to filter the array of objects and then sort the objects by the order of sortArray (btw, it would be easier if the data has the same type).
var items = [{ id: 1150, title: 'im tyler' }, { id: 1195, title: 'im josh' }],
sortArray = ['1195', '1150'].map(Number),
result = items
.filter(({ id }) => sortArray.includes(id))
.sort((a, b) => sortArray.indexOf(a.id) - sortArray.indexOf(b.id));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use array.sort and array.indexOf
var items = [
{id: '1150', title: 'im tyler'},
{id: '1195', title: 'im josh'}
];
var sortArray = [
'1195',
'1150'
];
items.sort((a, b) => sortArray.indexOf(a.id) - sortArray.indexOf(b.id));
console.log(items);
You can do that using map and filter, like this:
var ordered = sortArray.map(id => {
return items.filter(item => {
return id == item.id
});
});
I think this is silly question and simple but I can't find any result in google and other resource
I have array of object like this
const myArr = [
[{
id: 1,
price: 200,
}, {
id: 2,
price: 900,
}, {
id: 3,
price: 100,
}],
[{
id: 5,
price: 100,
}]
];
In other word I have an array and my array contain some array and each of inner array contain some object inside them
arr [ [ {},{},{} ] , [ {} ] ]
now I want get two thing
count of all products ?
sum of all products ?
*(each object = one product)
Flatten to a single array by spreading into Array.concat().
Use Array.reduce() to get the sum.
The count is flattened array's length.
const myArr = [[{"id":1,"price":200},{"id":2,"price":900},{"id":3,"price":100}],[{"id":5,"price":100}]];
const flattened = [].concat(...myArr);
const count = flattened.length;
const sum = flattened.reduce((s, o) => s + o.price, 0);
console.log('count', count);
console.log('sum', sum);
You can use spread to flat the array:
var myArr = [
[
{
id:1,
price:200,
},
{
id:2,
price:900,
},
{
id:3,
price:100,
}
],
[
{
id:5,
price:100,
}
]
];
var arr = [].concat(...myArr);
console.log('Length: ', arr.length);
var sum = arr.reduce((m, o) => m + o.price, 0);
console.log('Sum: ', sum);
You can use concat to wrap all objects within one single array.
Apply length property in order to find out the number of objects in the array and then reduce method to get the sum.
const myArr = [ [ { id:1, price:200, }, { id:2, price:900, }, { id:3, price:100, } ], [ { id:5, price:100, } ] ];
arr = myArr.reduce((acc, arr) => acc.concat(arr), []);
sum = arr.reduce((acc, item) => acc + item.price, 0);
console.log('count ' + arr.length);
console.log('sum ' + sum)
ES6
You can also use reduce method of array to get the required result
reduce can be used to iterate through the array, adding the current element value to the sum of the previous element values.
DEMO
const myArr = [[{id: 1,price: 200,}, {id: 2,price: 900,}, {id: 3,price: 100,}],[{id: 5,price: 100,}]];
let result = myArr.reduce((r,v)=>{
r.count += v.length;
r.sum += v.reduce((total,{price}) => total+price,0);
return r;
},{count:0,sum:0})
console.log(result);
.as-console-wrapper {max-height: 100% !important;top: 0;}
I am using a JavaScript library that has some code that expects a simple flat array of items like this...
var items = [
'item 1',
'item 2',
'item 3',
];
This is too limited for my project needs so I am editing the library to accept an array of object instead like this...
var items = [
{
id: 1,
name: 'Item 1',
image: 'img 1',
},
{
id: 2,
name: 'Item 2',
image: 'img 2',
},
{
id: 3,
name: 'Item 3',
image: 'img 3',
},
];
The library calls some code like this...
if (_helpers.inArray(val, this.options.items) || (val === '')) {
return val;
}
It check to see if a string is in the items array.
Because my items array is no longer a simple string value and is instead an object now. This breaks this part of the library code.
The code for the function it calls is this...
var _helpers = {
inArray: function(val, arr) {
return ($.inArray(val, arr) !== -1);
},
};
So I need some help in making my own _helpers.inArray(val, this.options.items) function which will check for a string value in an array of objects under the object property name
Any help appreciated
Could be something like this?
var _helpers = {
inArray: function(val, arr) {
for (var i = 0; i < arr.length; i++){
if (arr[i].name === val)
return true;
}
return false;
},
};
https://jsfiddle.net/z54qnukd/1/
Try mapping your array of objects back to the simple format:
var _helpers = {
inArray: function(val, arr) {
var mappedArr = $.map( items, function(item, index) {
return item.name;
});
return ($.inArray(val, mappedArr) !== -1);
},
};
https://jsbin.com/tihuyuquni/edit?html,output