it possible to sort and rearrange an array that looks like this:
items:[{
id: '5',
name: 'wa'
},{
id: '3',
name: 'ads'
},{
id: '1',
name: 'fdf'
}]
to match the arrangement of this object:
Item_sequence: {
"5": {index: 1},
"1": { index: 0 }
}
Here is the output I’m looking for:
items:[{
id: '1',
name: 'fdf'
},{
id: '5',
name: 'wa'
},{
id: '3',
name: 'ads'
}]
You could check if the index is supplied and if not take a lage value for sorting by delta of two items.
var data = { items: [{ id: '5', name: 'wa' }, { id: '3', name: 'ads' }, { id: '1', name: 'fdf' }] },
sequence = { 5: { index: 1 }, 1: { index: 0 } };
data.items.sort(({ id: a }, { id: b }) =>
(a in sequence ? sequence[a].index : Number.MAX_VALUE) -
(b in sequence ? sequence[b].index : Number.MAX_VALUE)
);
console.log(data.items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
JavaScript specifically, First you have to apply loop to your array "items":
`
let newArr = [];
items.map(obj=>{
//obj will be the element of items array, here it is an object.
if(Item_sequence.obj[id] !== undefined) {
/*this condition will be satisfied when id from items array will be present as a
key in Item_sequence array*/
insertAt(newArr, Item_sequence.obj[id] , obj)
}
else{
newArr.push(obj);
}
})
//After checking on whole array here you assign a newArr value to items array.
items=newArr;
Hope that it will help you.
Related
I have the object with the next structure:
let array = [
{
name: 'Name1',
items: [
{
name: 'Name1.1',
items: [
{ id: '1', name: 'Name1.1.1' },
{ id: '2', name: 'Name1.1.2' },
{ id: '3', name: 'Name1.1.3' },
...
],
},
{
name: 'Name1.2',
items: [
{ id: '4', name: 'Name1.2.1' },
{ id: '5', name: 'Name1.2.2' },
],
},
],
},
{
name: 'Name2',
items: [
{
name: 'Name2.1',
items: [
{ id: '6', name: 'Name2.1.1' },
{ id: '7', name: 'Name2.1.2' },
],
},
],
},
];
I want to get the branch without the sibling elements, searching by id. The desired result is the next structure by id = '4':
let array = [
{
name: 'Name1',
items: [
{
name: 'Name1.2',
items: [
{ id: '4', name: 'Name1.2.1' },
],
},
],
}
];
I could find only the end element of the tree ({ id: '4', name: 'Name1.2.1' }). But I don't understand how to get intermediate structures of the tree.
const test = (data, id) => {
if (!data || !data.length) return null;
for (var j = 0; j < data.length; j++) {
var result = data[j].items
? test(data[j].items, id)
: data[j].id
? data[j].id === id
? data[j]
: undefined
: undefined;
if (result !== undefined) {
return result;
}
}
return undefined;
};
test(array, '4');
You should indeed take a recursive approach, but your function currently can only return an id value (a string) or null or undefined. It never returns an array, yet that is what you expect to get.
When a solution is found as a base case, you need to wrap that solution in an array and plain object, each time you get out of the recursion tree.
Here is a working solution:
function getPath(forest, targetid) {
for (let root of forest) {
if (root.id === targetid) return [root]; // base case
let items = root.items && getPath(root.items, targetid);
if (items) return [{ ...root, items }]; // wrap!
}
}
// Example run:
let array = [{name: 'Name1',items: [{name: 'Name1.1',items: [{ id: '1', name: 'Name1.1.1' },{ id: '2', name: 'Name1.1.2' },{ id: '3', name: 'Name1.1.3' },],},{name: 'Name1.2',items: [{ id: '4', name: 'Name1.2.1' },{ id: '5', name: 'Name1.2.2' },],},],},{name: 'Name2',items: [{name: 'Name2.1',items: [{ id: '6', name: 'Name2.1.1' },{ id: '7', name: 'Name2.1.2' },],},],},];
console.log(getPath(array, '4'));
I have an array that is defined like this:
const arr = [
{
status: 'status1',
count: 2,
elements: [
{
id: '1',
},
{
id: '2',
},
],
},
{
status: 'status2',
count: 1,
elements: [
{
id: '3',
},
],
},
{
status: 'status3',
count: 1,
elements: [
{
id: '4',
},
],
},
];
The array is dynamic, but I know the status field and the id inside the elements. What I am trying to achieve is a new array, that contains all the same items, but looks like this instead:
const arr = [
{
status: 'status1',
count: 1,
elements: [
{
id: '1',
},
],
},
{
status: 'status2',
count: 2,
elements: [
{
id: '2',
},
{
id: '3',
},
],
},
{
status: 'status3',
count: 1,
elements: [
{
id: '4',
},
],
},
];
In other words, if status === status1, remove element with id === 2, set count to the length of elements array (or decrease by 1), take the element that has id === 2 and put it into elements array that has status === status2, set total count to the length of elements array .
I am not all that strong with iterating through nested elements and manipulating the array in these ways, but simpler concepts with array.filter/map etc seems okay, but I cannot wrap my head around all of this. :P
I would prefer to use vanilla JS, if possible. But I do have access to lodash if it makes things a lot easier.
Edit: When I mean vanilla JS, I refer to not using a ton of external libraries, but ES6 is what I use at this project.
My try consists of simply trying to filter arr on status, and then again on my id. Then I know what item I want to move. But it kind of stops there, and I also believe that it could be much more efficient:
const itemToMove = arr.filter(e => e.status === "status1")[0].elements.filter(e => e.id ==='2' )
I am not sure how to best proceed after this, thus asking for help.
You could find the source and target objects and splice the element.
const
move = (data, from, to, id) => {
const
find = value => ({ status }) => status === value,
source = data.find(find(from)),
target = data.find(find(to)),
index = source.elements.findIndex(o => o.id === id);
if (index === -1) return;
target.elements.push(...source.elements.splice(index, 1));
source.count--;
target.count++;
},
array = [{ status: 'status1', count: 2, elements: [{ id: '1' }, { id: '2' }] }, { status: 'status2', count: 1, elements: [{ id: '3' }] }, { status: 'status3', count: 1, elements: [{ id: '4' }] }];
move(array, 'status1', 'status2', '2');
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have nested array of objects that looks like this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 1 }, { id: 2 }],
[{ id: 4 }, { id: 5 }, { id: 6 }],
]
Since objects with id 1 and 2 are already together in nestedArray's first element I want to remove the second element and maintain other elements without petition as they are. The result should be like this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 4 }, { id: 5 }, { id: 6 }]
]
How do I write a filter function by id to get the expected result?
As I see in your example:
the id are unique in each subarray
duplicate sub-array elements only exist in the previous sub-array
if the first element of a sub-array exists in the previous sub-array then all the other elements must also be
const nestedArray =
[ [ { id: 1} , { id: 2} , { id: 3} ]
, [ { id: 1} , { id: 2} ]
, [ { id: 4} , { id: 5} , { id: 6} ]
]
function arrCleaning(arr)
{
for (let i=arr.length;i--;)
{
if (i>0 && arr[i-1].some(x=>x.id===arr[i][0].id) )
arr.splice(i,1)
}
}
arrCleaning( nestedArray )
// result
console.log( 'nestedArray = [' )
nestedArray.forEach(e=>console.log(' ',JSON.stringify(e).replaceAll('"',''),','))
console.log(' ]')
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display:none !important; }
Try this:
const nestedArray = [
[{ id: 1 }, { id: 2 }, { id: 3 }],
[{ id: 1 }, { id: 2 }]
]
var newArr = nestedArray.flat(2).filter((x, index, self) => index === self.findIndex((t) => (t.id === x.id)));
console.log(newArr);
I am fetching an array of objects as following :
const data =
[ { id: 0, company: 'nike', items: [{ id: 0, name: 'caret', price: 100}] }
, { id: 1, company: 'adidas', items: [{ id: 1, name: 'mobile phone', price: 300}] }
]
I want to filter that array of objects by checking the value of the property "name" inside the items array if it is "Caret" or not. If yes, I want to return the same array of objects with all its content but filtered. Which means, it will filter out the object whose item's name is not caret. How can I achieve this in javascript?!
I suppose you are looking for that ?
const data =
[{ id: 0, company: 'nike', items: [{ id: 0, name: 'caret', price: 100}]}
,{ id: 1, company: 'adidas', items: [{ id: 1, name: 'mobile phone', price: 300}]}
]
const filterName = (arr, name)=>arr.filter(el=>el.items.some(x=>x.name==name))
onlyCaret = filterName(data,'caret')
console.log( onlyCaret[0].company ) // nike
console.log( onlyCaret ) // row 0 with { ... company: 'nike' ..}
.as-console-wrapper { max-height: 100% !important; top: 0; }
You need to use Array.filter and then loop through your items for a match
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const data = [
{
id:0,
company: "nike"
items:[
name: "caret",
price:100
]
},
{
id:1,
company: "adidas"
items:[
name: "mobile phone",
price: 300
]
},
]
const filteredCompanies = data.filter((company)=>{
company.items.forEach((item)=>{
if(item.name === "nike") return true
})
})
I'm trying to wrap my head around transforming an array of "flat" objects, into a condensed but nested version:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
/*
desiredResult = [
{name: 'one', id:100, things: [
{thing: 1}, {thing: 2}, {thing:4}
]},
{name: 'two', id:200, things: [
{thing: 5}
]}
]
*/
// THIS DOES NOT WORK
const result = startingArray.reduce((acc, curr) => {
if (acc.name) {
acc.things.push(curr.thing)
}
return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };
}, {});
What am I not understanding?!
In your reduce callback, acc is not "each element of the array" (that's what curr is) or "the matching element in the results" (you have to determine this yourself), it's the accumulated object being transformed with each call to the function.
That is to say, when you return { name: curr.name, id: curr.id, things: [{thing: curr.thing}] };, it sets acc to that object for the next iteration, discarding whatever data was contained in it before - acc.name will only ever hold the last name iterated over and the results will never accumulate into anything meaningful.
What you want to do is accumulate the results in an array (because it's your desired output), making sure to return that array each iteration:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, curr) => {
let existing = acc.find(o => o.id == curr.id);
if(!existing) acc.push(existing = { name: curr.name, id: curr.id, things: [] });
existing.things.push({thing: curr.thing});
return acc;
}, []);
console.log(result);
Because of your desired result format this involves quite a few acc.find() calls, which is expensive - you can get around this in a concise way with this trick, using the first element of the accumulator array as a mapping of ids to references (also featuring ES6 destructuring):
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const result = startingArray.reduce((acc, {name, id, thing}) => {
if(!acc[0][id])
acc.push(acc[0][id] = { name, id, things: [] });
acc[0][id].things.push({thing});
return acc;
}, [{}]).slice(1); //slice off the mapping as it's no longer needed
console.log(result);
Ok, providing alternative way. Key point is that you accumulate an Object and later take only the values, so get an Array:
const startingArray = [
{ name: 'one', id: 100, thing: 1 },
{ name: 'one', id: 100, thing: 2 },
{ name: 'one', id: 100, thing: 4 },
{ name: 'two', id: 200, thing: 5 }
];
const res = startingArray.reduce((acc, curr) => {
if (acc[curr.name]) {
acc[curr.name].things.push({thing: curr.thing})
} else {
acc[curr.name] = {
name: curr.name,
id: curr.id,
things: [{thing: curr.thing}]
}
}
return acc
}, {})
console.log(Object.values(res))