I have to render an array of inputs out of data which would be fairly straightforward:
const [myInputs, setMyInputs] = useState([{id: 1, value: 'foo'},{id: 2, value: 'bar'}, ...])
myInputs.map(({id, value}) => <input key={id} value={value} />
the problem is that If I want to add an onChange function I have to find my object, remove it from the array, make a new object with the new values and insert it at the same position, same for every other modification I want to make to my data.
Is there a better way to accomplish the same effect (have an iterable where I can modify each value individually)?
Do it like this:
const [myInputs, setMyInputs] = useState({
nameOfInput1: {
id: 1,
value: 'foo'
},
nameOfInput2: {
id: 2,
value: 'bar'
},
})
Object.entries(myInputs).forEach(([key, field]) => (
<input
key={field.id}
value={field.value}
onChange={(newValue) => setMyInputs({ ...myInputs, key: { ...field, value: newValue } })}
/>
)
Convert the array to key value pairs. For Example:
{id: 1, value: 'foo'},{id: 2, value: 'bar'}
will be
const obj = {1: 'foo', 2: 'bar'}
So using the id you can delete, update or add the object.
delete obj[1]; //delete
obj[2] = 'new bar'; //update
obj[3] = 'new val'; //add
Also for rendering you can do Object.keys(obj) and map it to element.
Related
I am having an array like this :
arr = [ {id:0,name:Mark} , {id:1,name:Ron}, {id:2,name:Henry}, {id:3,name:Rose}].
I want to create an object like this :
obj1 = { Mark:false, Ron:false, Henry:false, Rose:flase }
I am using map to traverse through the array like this
let obj1 = {};
obj1 = arr.map((item)=> {
obj1[item.name] = false;
})
How can I achieve the following result?
You could map entries and build an object from the pairs.
const
data = [{ id: 0, name: 'Mark' }, { id: 1, name: 'Ron' }, { id: 2, name: 'Henry' }, { id: 3, name: 'Rose' }],
result = Object.fromEntries(data.map(({ name }) => [name, false]));
console.log(result);
Object.fromEntries() is probably the best idea. But you could also use reduce, if you got more operations on the array and want to stick to the "pipe" approach.
const arr = [
{ id: 0, name: 'Mark' },
{ id: 1, name: 'Ron' },
{ id: 2, name: 'Henry' },
{ id: 3, name: 'Rose' }
];
const objA = arr
.reduce((previous, { name }) => ({ ...previous, [name]: false }), {});
const objB = arr
.reduce((previous, { name }) => {
previous[name] = false;
return previous;
}, {});
The spreach operation {...obj} for objA does effectivly copy the object on each extension, which might not be desirable. But the modern JavaScript engines simplify those expressions anyways.
objB is the more standard approach for me. One additional benefit, in regards to Object.fromEntries() is that you can have some form of standard or default object / settings, which you can use as the start of the reduce (the second parameter) and evaluate in the collection function.
All three options are valid and depend on your code style.
Let's take 2 objects and let's say I want to dynamically add a key to the first object with the value of the second, and to do this I want to use the spread operator.
let object1 = { key: 'myKey1', value:1 };
let object2 = { field: 'key', displaValue:'chiave' };
something like this:
let object3 = {...object1, [object2.displayValue)]: object1[object2.field] }
But unfortunately I have this result with the undefined key:
{key: "myKey1", value: 1, undefined: "myKey1"}
Expected result:
{key: "myKey1", value: 1, chiave: "myKey1"}
There are two array of objects and i want to filter two values by iterating differently to get two different id.
Here is the example
1st array : list_of_products: [ { text: "Shoes", value: 1},{text:"Clothing", value: 2},{text:"Foods", value: 3}]
2nd Array: list_of_names: [{ text: "jim" , value: 1},{text:"Sim", value: 2},{text:"Tim",value:3}]
Now, i want to get the ids by filtering out two arrays based on names like this
product_name: "Clothing", person_name:"Tim"
Then i want to store the ids like this
const newIds = { product_id: 2,name_id: 3}
This i have tried:
const newProduct_name = list_of_products.find(name => name.text === product_name);
const newName = list_of_names.find(name => name.text === person_name);
storing it into new object like this
const values = {product_id: newProduct_name.value ,name_id: newName.value}
How to do this by minimal use of variables and faster execution?
Creating Maps or objects using the lookup values as keys lets you iterate each of your source arrays once and then have o(1) searches rather than using find() to iterate each array many times
const products= [ { text: "Shoes", value: 1},{text:"Clothing", value: 2},{text:"Foods", value: 3}],
names= [{ text: "jim" , value: 1},{text:"Sim", value: 2},{text:"Tim",value:3}];
const createMap = (arr) => new Map(arr.map(o => [o.text, o.value])),
prodMap = createMap(products),
namesMap = createMap(names);
const data = [{
product_name: "Clothing",
person_name: "Tim"
}];
const res = data.map(o => {
return {
product_id: prodMap.get(o.product_name),
name_id: namesMap.get(o.person_name)
};
})
console.log(res)
const obj ={
1: {name:"josh",age:2, symbol: "abc", id: 1},
2: {name:"mike",age:4, symbol: "efg", id: 2}
}
const search = (input) => {
return Object.values(obj).filter(item => {
return item.name.includes(input)
})
}
search("mi")
// returns: [ { name: 'mike', age: 4, symbol: 'efg', id: 2 } ]
How can I access the found objects id (id:1)
How can I get the found objects key (1: ...)
I am trying to find 1 and 2 of the object inside my array which matched my search input (see function)! In my filter I search for an object inside my array and see if one of those objects matches (or not) my search input. Then based on that I want to find the id of THAT object and its key
Thanks!
You had it right, except when you used Object.values you lost the object keys, check demo below
const obj ={
1: {name:"josh",age:2, symbol: "abc", id: 1},
2: {name:"mike",age:4, symbol: "efg", id: 2}
}
const search = (input) => {
return Object.keys(obj).filter(key => {
return obj[key].name.includes(input)
})
.map(foundKey => ({...obj[foundKey], key: foundKey }))
}
const result = search("mi")
console.log(result)
Change the search for this:
const search = input => Object.values(obj).findIndex(item => item.name.includes(input));
Your Search:
const index = search('mike');
Your ID:
const id = Object.keys(obj)[index];
Your Item:
const item = obj[id];
I have an array of objects and I want to get a new array from it that is unique based only on a single property, is there a simple way to achieve this?
Eg.
[ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
Would result in 2 objects with name = bill removed once.
Use the uniq function
var destArray = _.uniq(sourceArray, function(x){
return x.name;
});
or single-line version
var destArray = _.uniq(sourceArray, x => x.name);
From the docs:
Produces a duplicate-free version of the array, using === to test object equality. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iterator function.
In the above example, the function uses the objects name in order to determine uniqueness.
If you prefer to do things yourself without Lodash, and without getting verbose, try this uniq filter with optional uniq by property:
const uniqFilterAccordingToProp = function (prop) {
if (prop)
return (ele, i, arr) => arr.map(ele => ele[prop]).indexOf(ele[prop]) === i
else
return (ele, i, arr) => arr.indexOf(ele) === i
}
Then, use it like this:
const obj = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ]
obj.filter(uniqFilterAccordingToProp('abc'))
Or for plain arrays, just omit the parameter, while remembering to invoke:
[1,1,2].filter(uniqFilterAccordingToProp())
If you want to check all the properties then
lodash 4 comes with _.uniqWith(sourceArray, _.isEqual)
A better and quick approach
var table = [
{
a:1,
b:2
},
{
a:2,
b:3
},
{
a:1,
b:4
}
];
let result = [...new Set(table.map(item => item.a))];
document.write(JSON.stringify(result));
Found here
You can use the _.uniqBy function
var array = [ { id: 1, name: 'bob' }, { id: 2, name: 'bill' }, { id: 1, name: 'bill' },{ id: 2, name: 'bill' } ];
var filteredArray = _.uniqBy(array,function(x){ return x.id && x.name;});
console.log(filteredArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
In the above example, filtering is based on the uniqueness of combination of properties id & name.
if you have multiple properties for an object.
then to find unique array of objects based on specific properties, you could follow this method of combining properties inside _.uniqBy() method.
I was looking for a solution which didn't require a library, and put this together, so I thought I'd add it here. It may not be ideal, or working in all situations, but it's doing what I require, so could potentially help someone else:
const uniqueBy = (items, reducer, dupeCheck = [], currentResults = []) => {
if (!items || items.length === 0) return currentResults;
const thisValue = reducer(items[0]);
const resultsToPass = dupeCheck.indexOf(thisValue) === -1 ?
[...currentResults, items[0]] : currentResults;
return uniqueBy(
items.slice(1),
reducer,
[...dupeCheck, thisValue],
resultsToPass,
);
}
const testData = [
{text: 'hello', image: 'yes'},
{text: 'he'},
{text: 'hello'},
{text: 'hell'},
{text: 'hello'},
{text: 'hellop'},
];
const results = uniqueBy(
testData,
item => {
return item.text
},
)
console.dir(results)
In case you need pure JavaScript solution:
var uniqueProperties = {};
var notUniqueArray = [ { id: 1, name: 'bob' }, { id: 1, name: 'bill' }, { id: 1, name: 'bill' } ];
for(var object in notUniqueArray){
uniqueProperties[notUniqueArray[object]['name']] = notUniqueArray[object]['id'];
}
var uniqiueArray = [];
for(var uniqueName in uniqueProperties){
uniqiueArray.push(
{id:uniqueProperties[uniqueName],name:uniqueName});
}
//uniqiueArray
unique array by id property with ES6:
arr.filter((a, i) => arr.findIndex(b => b.id === a.id) === i); // unique by id
replace b.id === a.id with the relevant comparison for your case