I got the following array:
var arr = [{
"mainId": 1,
"parents": [{
"parent": 1
},
{
"parent": 2
}
]
},
{
"mainId": 2,
"parents": [{
"parent": 3
}]
}
]
I'm using this function to delete an specific parent in the parents array
var idToDelete = 2
arr.forEach(function (o) {
o.parents = o.parents.filter(s => s.id !== idToDelete
})
This is working fine. But when idToDelete = 3 I want to delete the complete main Item and start a function "startSomething"
So that I'm left with the following output
var arr = [{
"mainId": 1,
"parents": [{
"parent": 1
},
{
"parent": 2
}
]
}]
How could this be implemented?
You can map and then filter the top level array, here is an example:
var arr = [{
"mainId": 1,
"parents": [{
"parent": 1
},
{
"parent": 2
}
]
},
{
"mainId": 2,
"parents": [{
"parent": 3
}]
}
];
var idToDelete = 3;
arr = arr.map((v) => ({
...v,
parents: v.parents.filter(({
parent
}) => parent !== idToDelete)
}))
.filter((v) => v.parents.length);
console.log(arr);
Filter the parent array by whether it has a .length after mutating the children. Also make sure to use the .parent property (your objects have no .id property):
const startSomething = () => console.log('startSomething');
var arr =
[
{
"mainId": 1,
"parents": [
{
"parent": 1
},
{
"parent": 2
}
]
},
{
"mainId": 2,
"parents": [
{
"parent": 3
}
]
}
];
var idToDelete = 3;
arr.forEach(function (o) {
o.parents = o.parents.filter(s => s.parent !== idToDelete)
});
const newArr = arr.filter(({ parents }) => parents.length);
console.log(newArr);
if (newArr.length !== arr.length) {
startSomething();
}
You can use .filter() on the array itself (to remove the main object) with .some() to return true or false depending on whether it should be deleted or not:
const arr = [{ "mainId": 1, "parents": [{ "parent": 1 }, { "parent": 2 } ] }, { "mainId": 2, "parents": [{ "parent": 3 }] } ];
const removeObj = (arr, id, cb) => {
const res = arr.filter(({parents}) => !parents.some(({parent}) => parent === id));
const item_removed = res.length !== arr.length;
return (item_removed && cb(res), item_removed);
}
const startSomething = new_arr => console.log("Starting with arr", new_arr);
removeObj(arr, 3, startSomething);
.as-console-wrapper { max-height: 100% !important;} /* ignore */
Here's a alternative method, with a function that uses findIndex to find the object in the array.
Then splices the object if it only has 1 parent.
Or splices the parent from object if it has more than 1 parent.
Example snippet:
const deleteParent = (arr, id) =>
{
let idx = arr.findIndex(x=>x.parents.some(p=> p.parent === id));
if (idx >= 0 && arr[idx].parents.length === 1 ) {
let obj = arr[idx];
// remove object from array and do something
arr.splice(idx, 1);
doSomething(obj);
}
else if(idx >= 0){
let obj = arr[idx];
let parentIdx = obj.parents.findIndex(x=>x.parent==id);
// remove parent
obj.parents.splice( parentIdx, 1);
}
}
function doSomething (obj) { console.log(`Deleted mainId ${obj.mainId}`) }
var arr = [
{
"mainId": 1,
"parents": [
{
"parent": 1
},
{
"parent": 2
}
]
},
{
"mainId": 2,
"parents": [
{
"parent": 3
}
]
}
];
deleteParent(arr, 3);
console.log(JSON.stringify(arr));
deleteParent(arr, 2);
console.log(JSON.stringify(arr));
Related
The problem is how can I add two or n different list items into the order?
Then add them into a new list?
Anyone know is there a faster way to achieve this?
Thanks.
let resultList = [];
const list = [
{
"item": "aaa"
},
{
"item": "ddd"
},
];
const list2 = [
{
"item": "bbb"
},
{
"item": "ccc"
}
];
const list3 = [
{
"item": "xxx"
},
{
"item": "yyy"
}
];
// expected
resultList = [
{
"item": "aaa"
},
{
"item": "bbb"
},
{
"item": "xxx"
},
{
"item": "ddd"
},
{
"item": "ccc"
},
{
"item": "yyy"
},
]
If you can support new JavaScript features such as .flatMap(), you can map each object in list to an array containing the current object along with it's associated object from list2 like so:
const list = [{ "item": "aaa" }, { "item": "ddd" }];
const list2 = [ { "item": "bbb" }, { "item": "ccc" } ];
const res = list.flatMap((o, i) => [o, list2[i]]);
console.log(res);
This can be generalized for multiple lists:
const list = [{ "item": "aaa" }, { "item": "ddd" }];
const list2 = [ { "item": "bbb" }, { "item": "ccc" } ];
const list3 = [ { "item": "xxx" }, { "item": "yyy" } ];
const arr = [list, list2, list3];
const res = arr[0].flatMap((_, i) => arr.map(a => a[i]));
console.log(res);
const list = [
{
"item": "aaa"
},
{
"item": "ddd"
},
];
const list2 = [
{
"item": "bbb"
},
{
"item": "ccc"
}
];
var children = list.concat(list2);
children=children.sort(function(a, b) {
var x = a.item.toLowerCase();
var y = b.item.toLowerCase();
return x < y ? -1 : x > y ? 1 : 0;
})
console.log(children);
You can loop over first array and take the respective index value from other array as well and then push
const list = [{"item": "aaa"},{"item": "ddd"}];
const list2 = [{"item": "bbb"},{"item": "ccc"}];
let final = list.reduce((op, inp, index) => {
op.push(inp, list2[index])
return op
}, [])
console.log(final)
What if i have n list, you can create an array of n-1 list list ( except the first array ). loop over the first array and get to push value from each list loop over remaining and get value at particular index.
const list = [{"item": "aaa"},{"item": "ddd"}];
const list2 = [{"item": "bbb"},{"item": "ccc"}];
const list3 = [{"item": "eee"},{"item": "fff"}];
const list4 = [{"item": "ggg"},{"item": "hhh"}];
const remaining = [list2,list3,list4]
let final = list.reduce((op, inp, index) => {
op.push(inp, ...remaining.map(v=> v[index]))
return op
}, [])
console.log(final)
I have this object:
{
"value": "face",
"next": [
{
"value": "tace",
"next": [
{
"value": "tale",
"next": [
{
"value": "talk",
"next": []
}
]
},
{
"value": "tack",
"next": [
{
"value": "talk",
"next": []
}
]
}
]
},
{
"value": "fack",
"next": [
{
"value": "tack",
"next": [
{
"value": "talk",
"next": []
}
]
},
{
"value": "falk",
"next": [
{
"value": "talk",
"next": []
}
]
}
]
}
]
}
What is the best way to iterate over it and create this array of arrays:
[
["face", "tace", "tale", "talk"],
["face", "tace", "tack", "talk"],
["face", "fack", "tack", "talk"],
["face" ,"fack", "falk", "talk"]
]
I basically want to "flatten" the object into the array format by traversing down each branch of the object and producing an array of strings for each branch.
You can do this by creating recursive function using reduce method, that will store previous values and when there is no elements in next property it will current copy push to result array.
const data = {"value":"face","next":[{"value":"tace","next":[{"value":"tale","next":[{"value":"talk","next":[]}]},{"value":"tack","next":[{"value":"talk","next":[]}]}]},{"value":"fack","next":[{"value":"tack","next":[{"value":"talk","next":[]}]},{"value":"falk","next":[{"value":"talk","next":[]}]}]}]}
const flatten = (obj, prev = []) => {
const next = prev.concat(obj.value)
return obj.next.reduce((r, e) => {
if(e.next.length) r.push(...flatten(e, next))
else r.push(next.slice().concat(e.value));
return r;
}, [])
}
const result = flatten(data);
console.log(result);
You can use recursion with Array.forEach() to iterate the next property, and add the previous items. When next is empty, take everything, flatten, and push to the result:
const flatAll = (data) => {
const result = [];
const fn = ({ value, next }, prev = []) => {
if(next.length) next.forEach(o => fn(o, [prev, value]));
else result.push([prev, value].flat(Infinity));
};
fn(data);
return result;
}
const data = {"value":"face","next":[{"value":"tace","next":[{"value":"tale","next":[{"value":"talk","next":[]}]},{"value":"tack","next":[{"value":"talk","next":[]}]}]},{"value":"fack","next":[{"value":"tack","next":[{"value":"talk","next":[]}]},{"value":"falk","next":[{"value":"talk","next":[]}]}]}]};
const result = flatAll(data);
console.log(result);
You could use an independent recursive function and collect the last item and build an arrayof the given values for every level.
const
flat = (value, next) => next
.reduce((r, { value, next }) => {
if (next.length) r.push(...flat(value, next));
else r.push([value]);
return r;
}, [])
.map(q => [value, ...q]);
var data = { value: "face", next: [{ value: "tace", next: [{ value: "tale", next: [{ value: "talk", next: [] }] }, { value: "tack", next: [{ value: "talk", next: [] }] }] }, { value: "fack", next: [{ value: "tack", next: [{ value: "talk", next: [] }] }, { value: "falk", next: [{ value: "talk", next: [] }] }] }] },
result = flat(data.value, data.next);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have this,
var o = [{
"id": 1, // its actually a string in real life
"course": "name1",
// more properties
},
{
"id": 1, // its actually a string in real life
"course": "name2",
// more properties
}];
I want this,
var r = [{
"id": 1, // its actually a string in real life
"course": ["name1", "name2"],
}];
I am trying this,
var flattened = [];
for (var i = 0; i < a.length; ++i) {
var current = a[i];
if(flattened.)
}
but I am stuck, I am not sure what to do next, array will have more then 2 records but this was just an example.
THERE are more fields but I removed them for simplicity, I won't be using them in final array.
You could reduce the array and find the object.
var array = [{ id: 1, course: "name1" }, { id: 1, course: "name2" }],
flat = array.reduce((r, { id, course }) => {
var temp = r.find(o => id === o.id);
if (!temp) {
r.push(temp = { id, course: [] });
}
temp.course.push(course);
return r;
}, []);
console.log(flat);
The same by taking a Map.
var array = [{ id: 1, course: "name1" }, { id: 1, course: "name2" }],
flat = Array.from(
array.reduce((m, { id, course }) => m.set(id, [...(m.get(id) || []) , course]), new Map),
([id, course]) => ({ id, course })
);
console.log(flat);
This way you will get the data flattened in the shape you want
const o = [
{
id: 1,
course: "name1"
},
{
id: 1,
course: "name2"
},
{
id: 2,
course: "name2"
}
];
const r = o.reduce((acc, current) => {
const index = acc.findIndex(x => x.id === current.id);
if (index !== -1) {
acc[index].course.push(current.course);
} else {
acc.push({id:current.id, course: [current.course]});
}
return acc
}, []);
console.log(r);
You can do this with reduce and Object.entries. This example works for any number of properties:
const o = [
{ id: 1, course: 'name1', time: 'morning', topic: 'math' },
{ id: 1, course: 'name2', time: 'afternoon' },
{ id: 2, course: 'name3', time: 'evening' }
];
const result = o.reduce((out, { id, ...rest }) => {
out[id] = out[id] || {};
const mergedProps = Object.entries(rest).reduce((acc, [k, v]) => {
return { ...acc, [k]: [...(out[id][k] || []), v] };
}, out[id]);
out[id] = { id, ...mergedProps };
return out;
}, {});
console.log(result);
If you only care about the id and course fields, you can simplify to this:
const o = [
{ id: 1, course: 'name1', time: 'morning', topic: 'math' },
{ id: 1, course: 'name2', time: 'afternoon' },
{ id: 2, course: 'name3', time: 'evening' }
];
const result = o.reduce((out, { id, course }) =>
({ ...out, [id]: { id, course: [...((out[id] || {}).course || []), course] } })
, {});
console.log(result);
You could use .reduce to create an object of keys, and then use that object to set keys to be of the id. This way you can add to the same course array by targetting the id of the object. Lastly, you can get the values of the object to get your result.
See example below:
var o = [{
"id": 1,
"course": "name1",
"foo": 1
},
{
"id": 1,
"course": "name2",
"bar": 2
}];
var res = Object.values(o.reduce((acc, {id, course, ...rest}) => {
if(id in acc)
acc[id] = {...acc[id], course: [...acc[id].course, course], ...rest};
else acc[id] = {id, course: [course], ...rest};
return acc;
}, {}));
console.log(res);
function merge(array, key = 'id') {
const obj = {}
for(const item of array) {
const existing = obj[item[key]]
if(existing) {
for(const [name, value] of Object.entries(item)) {
if(name === key) continue;
if(existing[name]) {
existing[name] = [ ...(existing[name].$custom ? existing[name] : [existing[name]]), value ]
existing[name].$custom = true;
} else {
existing[name] = value;
}
}
} else {
obj[item[key]] = { ...item }
}
}
return Object.values(obj)
}
var o = [
{
"id": 1,
"single": "test"
},
{
"id": 1,
"course": "name1",
"multifield": "test"
},
{
"id": 1,
"course": "name2"
},
{
"id": 1,
"newfield": "test"
}, {
"id": 2,
"anotherid": "test",
"array": [1,3,4]
}, {
"id": 2,
"array": "text"
}];
console.log(merge(o))
You can use reduce to accumulate the results. Search in the current result (accumulator a) for an object (el) with the same id, if found, append course to existing object and return the same accumulator, otherwise put into the accumulator with course as an array.
var res = o.reduce((a, {id,course}) => {
var found = a.find(el => el.id == id);
return found ? found.course.push(course) && a : [...a, {id, course: [course]}];
}, []);
I currently have an array that looks like this:
var array = [
{
"name": "a",
"age": 1,
"siblings": 3
},
{
"name": "b",
"age": 3,
"siblings": 5
},
{
"name": "a",
"age": 1,
"siblings": 2
}
]
I want to create a function that takes 2 values, and returns a new array containing the objects that match those two values.
var name = "a";
var age = 1;
someFunction(name, age);
And returns something that looks like this:
newArray = [
{
"name": "a",
"age": 1,
"siblings": 3
},
{
"name": "a",
"age": 1,
"siblings": 2
}
]
I have tried using the filter method and the reduce methods but no success. If someone could help me or point me in the right direction, I would greatly appreciate that.
var array = [
{
"name": "a",
"age": 1,
"siblings": 3
},
{
"name": "b",
"age": 3,
"siblings": 5
},
{
"name": "a",
"age": 1,
"siblings": 2
}
]
var result = array.filter(function(obj) {
return obj.name === "a" && obj.age === 1;
});
return result[0];
}
console.log(result);
You could take an array with the wanted key/value pair for searching.
Take Array#filter with a check for the predicates with Array#every.
var array = [{ name: "a", age: 1, siblings: 3 }, { name: "b", age: 3, siblings: 5 }, { name: "a", age: 1, siblings: 2 }],
search = [['name', 'a'], ['age', 1]],
result = array.filter(object => search.every(([key, value]) => object[key] === value));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
here is your working function
function someFunction (name, age) {
return array.filter(val => val.name == name && val.age == age)
}
In the Array#filter callback, just compare the name & age of current element with those of the params you passed.
var array = [{"name":"a","age":1,"siblings":3},{"name":"b","age":3,"siblings":5},{"name":"a","age":1,"siblings":2}]
var name = "a";
var age = 1;
function someFunction(name, age){
return array.filter((obj) => obj.name === name && obj.age === age)
}
console.log(someFunction(name, age));
You can also use Array#reduce. Just add the matching object in the accumulator array and return it.
var array = [{"name":"a","age":1,"siblings":3},{"name":"b","age":3,"siblings":5},{"name":"a","age":1,"siblings":2}]
var name = "a";
var age = 1;
function someFunction(name, age){
return array.reduce((acc, obj) => {
if(obj.name === name && obj.age === age)
acc.push(obj);
return acc;
}, []);
}
console.log(someFunction(name, age));
Use the filter function
var array = [
{
"name": "a",
"age": 1,
"siblings": 3
},
{
"name": "b",
"age": 3,
"siblings": 5
},
{
"name": "a",
"age": 1,
"siblings": 2
}
]
var name = "a";
var age = 1;
someFunction(name, age);
function someFunction(name,age)
{
console.log(array.filter((e)=>e.name==name && e.age==age?true:false
))}
Try this
let array = [
{
"name": "a",
"age": 1,
"siblings": 3
},
{
"name": "b",
"age": 3,
"siblings": 5
},
{
"name": "a",
"age": 1,
"siblings": 2
}
];
function someFunction(name, age) {
let newArray = [];
array.forEach(function(arr) {
let nameMatch = false;
let ageMatch = false;
let obj = arr;
for(key in obj) {
if(obj.hasOwnProperty(key)) {
if(key === 'name') {
// console.log('name key i am', key);
let nameValue = obj[key];
if(nameValue === name) {
nameMatch = true;
// console.log('name match', nameValue, name);
}
} else if(key === 'age') {
let ageValue = obj[key];
if(ageValue === age) {
// console.log('age match', ageValue, age);
ageMatch = true
}
}
}
}
if(ageMatch && nameMatch) {
// console.log('true');
newArray.push(arr);
// console.log(arr);
}
});
return newArray;
}
let name = "a";
let age = 1;
let myArr = someFunction(name, age);
console.log('My Arr', myArr);
I'm trying to merge objects with the same key value into one and count them. Is it even possible?
var array = {
"items": [{
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 10,
"id": "111",
"name": "BlackCat",
}, {
"value": 15,
"id": "777",
"name": "WhiteCat",
}]
}
Desired output:
var finalArray = {
"items": [{
"value": 10,
"id": "111",
"name": "BlackCat",
"count": 2,
}, {
"value": 15,
"id": "777",
"name": "WhiteCat",
"count": 1,
}]
}
You can use reduce on your items array:
var combinedItems = array.items.reduce(function(arr, item) {
var found = false;
for (var i = 0; i < arr.length; i++) {
if (arr[i].id === item.id) {
found = true;
arr[i].count++;
}
}
if (!found) {
item.count = 1;
arr.push(item);
}
return arr;
}, [])
Fiddle: https://jsfiddle.net/6wqw79pn/
You could use a for loop:
var finalArray = [];
for (var i in array.items) {
var item = array.items[i];
var existingItem = finalArray.find(function(element){
return (element.id == item.id);
});
if (!existingItem) {
existingItem = {};
finalArray.push(existingItem);
} else {
if (!existingItem.count)
existingItem.count = 2;
else
existingItem.count++;
}
for (var j in item) {
existingItem[j] = item[j];
}
}
Working example: https://jsfiddle.net/mspinks/5kowbq4j/3/
Basically you could use a hash table with the value of id as key and count.
var object = { items: [{ value: 10, id: "111", name: "BlackCat", }, { value: 10, id: "111", name: "BlackCat", }, { value: 15, id: "777", name: "WhiteCat", }] },
result = object.items.reduce(function (hash) {
return function (r, o) {
if (!hash[o.id]) {
hash[o.id] = { value: o.value, id: o.id, name: o.name, count: 0 };
r.push(hash[o.id]);
}
hash[o.id].count++;
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Underscore js will be able to solve your problem very easily
var groups = _.groupBy(array.items, function(item){
return item.value + '#' + item.id + '#' + item.name;
});
var data = {'items' : []};
_.each(groups,function(group){
data.items.push({
'value' : group[0].value,
'id' : group[0].id,
'name' : group[0].name,
'count' : group.length
})
})
console.log(data)