is there any other way to write update an item in array of object other than below code?
const updateTodo = (list, updated) => {
const index = list.findIndex(item => item.id === update.id)
return [
...list.slice(0,index),
updated,
...list.slice(index+1)
]
}
Wait, is above function even working? https://jsbin.com/sifihocija/2/edit?js,console
The way you are doing it, is the right way to do it. However it is not working for you because in your case updated is an array and not an object and hence you only need to access the id of the first element of the array
const updateTodo = (list, updated) => {
const index = list.findIndex(item => return item.id === updated[0].id)
return [
...list.slice(0,index),
updated[0],
...list.slice(index+1)
]
}
JSBIN
However I prefer the library immutability-helper to perform any updates on the data you can do that like
import update from 'immutability-helper';
const updateTodo = (list, updated) => {
const index = list.findIndex(item => return item.id === updated[0].id)
return update(list, {
[index]: {
$set: updated[0];
}
})
}
One advantage of using immutabilty-helper is that its gives more control when the data is highly nested
You are doing to much. No need to manipulate the array if you know the index.
const items = [{id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}];
items[2] = {id: 4, value: 4};
console.log(items); //last element changed
if you care about no side effects copy the array before
const items = [{id: 1, value: 1}, {id: 2, value: 2}, {id: 3, value: 3}];
const copy = items.slice();
copy[2] = {id: 4, value: 4};
return copy;
The simplest way to update(addition/deletion) an array is to use splice method.
it takes the first argument as the index, second as the no of elements you want to remove and next arguments for the addition.
Related
I have an array of objects like this:
const myArr = [{id: 1, ...}, {id: 2, ...}, {id: 3, ...}];
and I have an object like this:
const myObj: {id: 2, someNewField};
I want to replace this new object for the one with the same ID in the original array, how can I do this?
I tried doing it like this:
const index = myArr.findIndex(item => item.id === myObj.id);
const filteredArr = myArr.filter(item => item.id !== myObj.id);
filteredArr.splice(index, 0, myObj);
It works but maybe there's a better way to do it
Instead of finding the index and filtering you could always use .map to return a new array.
const myObj = { id: 2, new: 1 };
const myArr = [{ id: 1 }, { id: 2 }, { id: 3 }];
const newArr = myArr.map(v => {
return v.id === myObj.id ? myObj : v;
});
It depends on what you would like to do if the item is not found in the array, as this will only replace.
By better if you mean faster method, here is one,
for(let i = 0;i<myArr.length; i++) {
if(myArr[i].id === myObj.id) {
myArr[i] = myObj;
break;
}
}
This is faster than your method because we are using for loop instead of .filter() or .findIndex() which is slower than regular for loop.
If you mean the most compact then you can do this,
myArr[myArr.findIndex(item => item.id === myObj.id)] = myObj;
Note that this approach will fail if there is no item with the given object key.
I created a sample code to demo my problem, the actual data is much bigger
const arr = [{
id: 1
}, {
id: 2,
items: [{
id: 1
}]
}]
const target = 2
const nextIndex = 1
newArr = arr.map(o => o.id === target ? ({
...o,
items: [...o.items, {
id: 'new id'
}]
}) : o);
console.log(newArr);
How to insert {id: 'new id'} by index? Above code is appending onto items array. Assuming I have a click event, user can insert the position of {id: 'new id} by index, I can't use append as it doesn't replace existing object.
expected output
[{
id: 1
}, {
id: 2,
items: [{
id: 1
},{
id: 'something'
}]
Above code doesn't work, adding new item to items array without using index.
Try to pass index from onClick event
functionName = (i) => { //where i is index from onclick event
arr.map( o, index) => {
if(i === index)
{
const obj = { //object
id: 'new id'
}
arr[i].push(obj) // push object at given index from onClick
}
}
}
The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements
const target = 2;
int index = arr.findIndex(v => v.id == target);
if (index > -1) {
arr.splice(index, 1, {id: 'new id'}); // replace 1 with 0 if you just want to insert.
}
let obj = {
tom: {
id: 0
},
david: {
id: 1
},
john: {
id: 2
}
}
let ids = [1, 2]
I want to filter the obj based on ids.
The result I want is
{
david: {
id: 1
},
john: {
id: 2
}
}
Because ids above is [1, 2].
I want to do this with Ramda.js.
Plase help me.
Ok, I'm sorry.
I did something like this.
let obj2 = {}
ids.forEach((x) => {
obj2 += R.filter(y => y.id === x, obj)
})
obj = obj2
But, it is not correct.
And I don't want to use forEach.
I want to do with Ramda.js .
You can do this only using Javascript, first you can create a set with the ids you want to keep (check if set has an element is O(1)). Then, you can loop on the original object and add the key with his value on a new object if the set has the related id:
let obj = {
tom: {id: 0},
david: {id: 1},
john: {id: 2}
}
let ids = [1, 2];
const filterByIds = (obj, ids) =>
{
let idsSet = new Set(ids);
let filteredObj = {};
for (k in obj)
{
if (idsSet.has(obj[k].id))
filteredObj[k] = obj[k];
}
return filteredObj;
}
console.log(filterByIds(obj, ids));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Update to use Ramda:
With Ramda you can do like this:
let obj = {
tom: {id: 0},
david: {id: 1},
john: {id: 2}
}
let ids = [1, 2];
let idsSet = new Set(ids);
const hasValidId = o => idsSet.has(o.id);
let res = R.filter(hasValidId, obj);
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Easy if you read the documentation here
You can do it in pure JavaScript by using Object.entries and destructuring with includes like so:
let obj = {
tom: {
id: 0
},
david: {
id: 1
},
john: {
id: 2
}
};
let ids = [1, 2];
let result = {};
Object.entries(obj).forEach(([name, { id }]) => {
if (ids.includes(id)) {
result[name] = { id: id };
}
});
console.log(result);
Generally speaking, you should strive to work with data structures that help you rather than work against you.
With a simplified data structure such as this one below:
const obj = [
{id: 0, name: 'tom'},
{id: 1, name: 'david'},
{id: 2, name: 'john'}
]
You could use innerJoin:
innerJoin((cur, id) => cur.id === id, obj, [1, 2])
How to convert your original data structure into a simplified one?
It can be a two-step process with Ramda:
Split your object into an array of key/value pairs with toPairs:
{tom:{id:0}} ~> [['tom', {id: 0}]]
Map each pair into an object:
[['tom', {id: 0}]] ~> [{name: 'tom', id: 0}]
const obj = {
tom: {
id: 0
},
david: {
id: 1
},
john: {
id: 2
}
}
const convert = R.compose(R.map(([name, id]) => ({name, ...id})), R.toPairs);
console.log(convert(obj))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
Try This:
let obj = { tom: { id: 0 }, david: { id: 1}, john: {id: 2} }
let ids = [1, 2] ;
let result = {} ;
for ( var o in obj ) {
if (ids.includes(obj[o].id))
result[o] = obj[o];
}
console.log(result) ;
Unless this is an exercise in learning Ramda, beware of the idea of wanting to do this in Ramda. I'm one of the primary authors of Ramda, and a big fan, but I need to stress that it's simply a toolkit than can help in some situations. When it helps, great, but it shouldn't be a goal.
Now, I do think it can help here. This is what I would do with Ramda:
const matchIds = (obj, ids) => filter(propSatisfies(includes(__, ids), 'id'), obj)
let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}}
let ids = [1, 2]
console.log(matchIds(obj, ids))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {__, filter, propSatisfies, includes} = R
</script>
An alternative, especially if the list of ids is less likely to change than the object, is this:
const matchIds = (ids) => filter(propSatisfies(includes(__, ids), 'id'))
let obj = {tom: {id: 0}, david: {id: 1}, john: {id: 2}}
let ids = [1, 2]
console.log(matchIds(ids)(obj))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {__, filter, propSatisfies, includes} = R
</script>
There are some reasons not to like the placeholder ('__'). If you feel that way, you can replace includes(__, ids) with flip(includes)(ids).
Update
I don't take my own advice here. While I still would use Ramda for the filter, there is no need for propSatisfies here. A simple lambda would be perfectly fine:
const matchIds = (ids) => filter(({id}) => ids.includes(id))
This is much cleaner and more readable, at least once you're used to the Ramda norm of partial application. (filter takes two arguments: the predicate function and the object to filter with it. Since we only supply the first, this gives us back a function expecting the second. When we call that resulting function with the object, the filtering happens.)
The reason I would still use Ramda's filter is that there is no direct built-in version of it as applied to objects. Ramda supplies a simple alternative to writing a one-off object filtering.
Let's say I have an array as follows:
types = ['Old', 'New', 'Template'];
I need to convert it into an array of objects that looks like this:
[
{
id: 1,
name: 'Old'
},
{
id: 2,
name: 'New'
},
{
id: 3,
name: 'Template'
}
]
You can use map to iterate over the original array and create new objects.
let types = ['Old', 'New', 'Template'];
let objects = types.map((value, index) => {
return {
id: index + 1,
name: value
};
})
You can check a working example here.
The solution of above problem is the map() method of JavaScript or Type Script.
map() method creates a new array with the results of calling
a provided function on every element in the calling array.
let newArray = arr.map((currentvalue,index,array)=>{
return Element of array
});
/*map() method creates a new array with the results of calling
a provided function on every element in the calling array.*/
let types = [
'Old',
'New',
'Template'
];
/*
let newArray = arr.map((currentvalue,index,array)=>{
return Element of array
});
*/
let Obj = types.map((value, i) => {
let data = {
id: i + 1,
name: value
};
return data;
});
console.log("Obj", Obj);
Please follow following links:
TypeScript
JS-Fiddle
We can achieve the solution of above problem by for loop :
let types = [
"One",
"Two",
"Three"
];
let arr = [];
for (let i = 0; i < types.length; i++){
let data = {
id: i + 1,
name: types[i]
};
arr.push(data);
}
console.log("data", arr);
I don't know how to write the title properly, pardon me on that.
Basically I have a list of array of object that's coming from a place, I need to map them together. How how with my code below I can't make it.
const person = [
{name:'hello',id:1},
{name:'javascript',id:2},
{name:'world',id:3}
];
const selected = [2,3];
const normalized = person.map((obj,i) => obj.id === selected[i] ? Object.assign({}, obj, {checked:true}) : obj);
console.log(normalized)
https://jsfiddle.net/q9g0kazx/1/
I need to add an extra property base on the selected array. Why above code doesn't work?
If I understand you correctly, just iterate through the array using forEach and add the property if needed.
const person = [
{name: 'hello', id: 1},
{name: 'javascript',id: 2},
{name: 'world',id: 3}
];
const selected = [2,3];
person.forEach(p => {
if (selected.includes(p.id)) {
p.checked = true;
}
});
console.log(person);
Or you can use map like this:
const person = [
{name: 'hello', id: 1},
{name: 'javascript',id: 2},
{name: 'world',id: 3}
];
const selected = [2,3];
person.map(p => {
if (selected.includes(p.id)) {
p.checked = true;
}
return p;
});
console.log(person);
Notice that you have to return the object (person in our case)
You can do this:
Check if the the id in the array is present in the selected array by:
selected.includes(obj.id)
So, includes returns true if the obj.id was present in the selected array. If present(yes) then your Object.assignpart of code executes.
The reason your code was not working was because your person array and selected array don't have same number of elements(count) and perhaps not in the order as well.
So person[0] id which is 1 doesn't match with selected[0] id which 2 and so on.
const person = [{
name: 'hello',
id: 1
},
{
name: 'javascript',
id: 2
},
{
name: 'world',
id: 3
}
];
const selected = [2, 3];
const normalized = person.map((obj, i) => selected.includes(obj.id) ? Object.assign({}, obj, {
checked: true
}) : obj);
console.log(normalized);