javascript array find value base on id [duplicate] - javascript

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 4 years ago.
I have an array of json objects:
[ {id:0, name:'A'}, {id:1, name:'B'}...{id:n, name:'N'} ]
How do i get the value (name) base on a given id, without iterating the array? Perhaps using map or some filter method...

const arr = [ {id:0, name:'A'}, {id:1, name:'B'},{id:3, name:'N'} ];
const inputId = 1;
const foundObj = arr.find(({ id }) => id === inputId);
if (foundObj) console.log(foundObj.name);
This still does iterate the array internally, though (as any method will).

This find method will find object based on your object property and value.
ArrayName.find(x => x.id === 0);

let array = [ {id:0, name:'A'}, {id:1, name:'B'}, {id:'n', name:'N'} ]
//To search in array we must iterate. But if you want to optimise performance for multiple searches you can map it to object by id.
let map = array.reduce((acc,element)=>{acc[element.id]=element;return acc;},{})
console.log(map[0])
console.log(map[1])
console.log(map.n) //As n was used as id.

Maps take one iteration to construct. Value retrieval thereon is sublinear.
// Input.
const input = [{id: 0, name:'A'}, {id: 1, name:'B'}, {id: 13, name:'N'}]
// To Map.
const toMap = (A) => new Map(A.map(x => [x.id, x]))
// Output.
const output = toMap(input)
// Proof.
console.log(output.get(0))
console.log(output.get(1))
console.log(output.get(13))

When you want to find an element in a collection, array might not be the best choice, objects or maps are much better in that case.
Each time you have to find an element, you would have to iterate over the array which would take O(n) time.
To avoid this, you could have an API layer in the middle, to convert your array into an a data structure which maps values by unique keys. You could achieve this by a plain Javascript Object.
That way you could find your element by id in O(1) without any iteration.
//original data
let arr = [ {id:0, name:'A'}, {id:1, name:'B'}, {id:2, name:'N'} ];
//convert it into object
let obj = arr.reduce((acc, curr) => {
acc[curr.id] = curr;
return acc;
}, {});
//modified data
{ 0: { id: 0, name: 'A' },
1: { id: 1, name: 'B' },
2: { id: 2, name: 'N' } }
//Now, you can look up value on any id as
obj[id].name;

Related

JavaScript Replacing Object in Array with ID Number

So I have a series of objects that are pulled from an API and inputted into an array, something like such:
array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 1, name: "Second", relationship: "Friend"}
]
The user is allowed to add and remove objects to the list freely (they will appear within a Vue.JS DataTable), and said user is allowed a maximum of 4 objects within the array (lets say 4 "friends")
How should I go about implementing a function that searches the existing array (say, if its populated from the API), and inputs the new object with the corresponding ID that is missing (so if the user deletes the object with the id 2, and adds another, it will search said array with objects, find the missing id 2 slot in the array, and input the object in its place)?
Previously I have gone about it via implement array.find() with conditionals to see if the array contains or does not contain the certain id value, however, it searches through each entry and can end up inserting the same object multiple times. Another method I haven't attempted yet would be having a separate map that contains ids, and then when a user removes an object, having it correspond with the map, and vice versa when adding.
Any suggestions? Thanks
Instead of an array, I'd keep an object in data. Have it keyed by id, like this:
let objects = {
0: { id: 0, name: 'name0', relationship: 'relationship0' },
1: { id: 1, name: 'name1', relationship: 'relationship1' },
}
Integer keys in modern JS will preserve insertion order, so you can think of this object as ordered. The API probably returns an array, so do this...
// in the method that fetches from the api
let arrayFromApi = [...];
this.objects = array.reduce((acc, obj) => {
acc[obj.id] = obj; // insertion order will be preserved
return acc;
}, {});
Your UI probably wants an array, so do this (refer to "array" in the markup):
computed: {
array() {
return Object.values(this.objects);
},
To create a new object, insert it in order, minding the available keys. Note this is a linear search, but with small numbers of objects this will be plenty fast
methods: {
// assumes maxId is const like 4 (or 40, but maybe not 400)
createObject(name, relationship) {
let object = { name, relationship };
for (let i=0; i< maxId; i++) {
if (!this.objects[i]) {
object.id = i;
this.objects[i] = object;
break;
}
}
try this,
let array = [
{id: 0, name: "First", relationship: "Friend"},
{id: 4, name: "Second", relationship: "Friend"},
{id: 2, name: "Second", relationship: "Friend"},
]
const addItem = (item) => {
let prevId = -1
// this is unnecessary if your array is already sorted by id.
// in this example array ids are not sorted. e.g. 0, 4, 2
array.sort((a, b) => a.id - b.id)
//
array.forEach(ob => {
if(ob.id === prevId + 1) prevId++
else return;
})
item = {...item, id: prevId + 1 }
array.splice(prevId+1, 0, item)
}
addItem({name: "x", relationship: "y"})
addItem({name: "a", relationship: "b"})
addItem({name: "c", relationship: "d"})
console.log(array)
You can simply achieve this with the help of Array.find() method along with the Array.indexOf() and Array.splice().
Live Demo :
// Input array of objects (coming from API) and suppose user deleted 2nd id object from the array.
const arr = [
{id: 0, name: "First", relationship: "Friend" },
{id: 1, name: "Second", relationship: "Friend" },
{id: 3, name: "Fourth", relationship: "Friend" }
];
// find the objects next to missing object.
const res = arr.find((obj, index) => obj.id !== index);
// find the index where we have to input the new object.
const index = arr.indexOf(res);
// New object user want to insert
const newObj = {
id: index,
name: "Third",
relationship: "Friend"
}
// Insert the new object into an array at the missing position.
arr.splice(index, 0, newObj);
// Output
console.log(arr);

Creating two arr with same intersect

Right now I need to merge the string into one.
This is my try ->
After this merge i got example of array ->
[
[{id: 1, name: "One"}],
[{id: 2, name : "two"}]
]
problem is newData because always print new array.
I need to data be like ->
[
{id: 1, name: "One"},
{id: 2, name : "two"}
]
What i am try, with foreEach ->
newState((oldData) => [...oldData, newData.forEach((new) => new)]);
No work.
Also what I am try
let filteredArray = newData.map(data => data);
Also no work, why?
Every time I get new information inside array newData....
I need solution to get only result inside array and print to
newState((oldData) => [...oldData, newResultWhichIsObject]);
Also some time my newData have few object inside array
The map method isn't the right method to use in your case. Map method will take as an entry an array of n elements and mutate it into an array of n element, on which an operation was applied. See MDN documentation
You should use the reduce method, which provides the ability to construct a brand new array from an empty one, here is the snippet :
const baseArray = [
[{id: 1, name: "One"}],
[{id: 2, name : "two"}]
];
const flattenedArray = baseArray.reduce((acc, curr) => ([...acc, ...curr]), []);
// For demo purpose, console.log
console.log(flattenedArray);
Reduce array method is a bit tricky, that is why I invite you to read the documentation carefully and play with it.
You can use .flat() method. Try this
const newData = [
[{id: 1, name: "One"}],
[{id: 2, name : "two"}]
];
console.log(newData.flat())

How to filter an array of objects with another array, based on values in the arrays of objects's property? [duplicate]

This question already has answers here:
Javascript: filter array of objects by array of strings
(4 answers)
Closed 1 year ago.
I have an array of objects named profiles:
[{id: 0, subcategories: ['A', 'B', 'C']}, {id: 1, subcategories: ['A']}]
I have an array named tags: ['B']
I want to filter profiles, only keeping profiles that have a value in tags. In this case, profile with id = 0 would be saved.
This is what I have tried so far and it doesn't seem to be working:
let filtered_profiles = profiles.filter((profile) =>
tags.includes(profile.subcategories)
);
This is my approach. If profiles subcategories includes at least one tag, push it into the result object.
let profiles = [{id: 0, subcategories: ['A', 'B', 'C']},
{id: 1, subcategories: ['A']}];
let tags = ['B'];
let result = [];
profiles.forEach(function (p){
let copied = false;
tags.forEach(function (t) {
if (p.subcategories.includes(t) && !copied) {
result.push(p);
copied = true;
}
})
});
console.log(result);

How to convert objects inside array to nested array JavaScript?

I have an array containing objects that every element but the last one are objects, but I want to convert them into an array of arrays and add the last element.
To be more explicit here is how I have it:
[
{ 0: [1,2], 1: [6,2], name: "" },
{ 0: [3,4], 1: [2,2], name: "" }
]
and the result I want is this one:
[
{ multipolygon: [ [1,2], [6,2] ], name: ""},
{ multipolygon: [ [3,4], [2,2] ], name: ""}
]
Each single array contained inside the original array is converted into an array of those arrays.
I have tried doing this:
const zonesArray = zones.map(el => Object.values(el)) // obj => array
const polygons = zonesArray.filter(el => el.pop()) // array without name
to get all the arrays contained inside the obj but then I realized how can I replace this into the original objects.
I have tried to modify the groupBy function found on MDN:
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(obj)
return acc
}, {})
}
But I can't seem to find the answer
It doesn't look like you're trying to group by a property, you're trying to transform each object in the array separately - which can be done by taking the name and the numeric properties together when mapping, then returning the shape of the new object:
const arr = [
{ 0: [1,2], 1: [6,2], name: "" },
{ 0: [3,4], 1: [2,2], name: "" }
];
const result = arr.map(({ name, ...rest }) => ({
name,
multipolygon: Object.values(rest)
}));
console.log(result);

Reduce an Array of Objects With Duplicate IDs by a Second Date Property

I have an array of objects and all of them have at least 1 other object with the same ID. I am trying to reduce this array to only return the object with the most recent date. An example array of what I'm dealing with:
var arrObj = [
{id: 1, startDate: 2019-10-09},
{id: 1, startDate: 2019-10-05},
{id: 1, startDate: 2019-09-30},
{id: 2, startDate: 2018-08-05},
{id: 2, startDate: 2018-09-05}
]
Output I am trying to achieve:
var newArrObj = [
{id: 1, startDate: 2019-10-09},
{id: 2, startDate: 2018-09-05}
]
I have found a lot of examples of reducing or removing duplicate objects by ID completely, but I can't seem to find an example of first identifying the objects with the same ID, then reducing by a second property. Unfortunately I keep finding myself creating a lot of nested for loops. Is there an elegant way to do this? I need to be able to do it in ES5 or earlier.
var uniqueIDs = [];
for (a in arrObj) {
if(uniqueIDs.indexOf(arrObj[a].id) != -1) {
uniqueIDs.push(arrObj[a].id);
}
}
var newArrObj = [];
for(b in uniqueIDs) {
var uniqueId = uniqueIDs[b];
var uniqueIdObjs = arrObj.filter(function(x) {
return x.id === uniqueId;
});
for(c in uniqueIdObjs) {
var objDate = uniqueIdObjs[c].startDate;
//This is where I get stuck
}
}
I'd go with your style of first filtering the IDs to uniques, because thats the easy part.
Then you can simply chain array function so extract the last date:
map over the unique IDs so that your returns create a new array at the end.
filter the original array to include only object with the ID we workin on now
sort the temporary array created with all objects of the same ID so that the mostrecent one would be first, and return the first element.
let finalResult = uniqueIDs.map( id => {
return arrayObj.filter( obj => obj.id === id )
.sort((a, b) => new Date(b.startDate) - new Date(a.startDate))[0];
Tada! finalResult is now and array containing only one object with the most recent date for every ID :)
You can sort the array by date, get an array of ids and dedupe it, then map the deduped array to replace them with actual objects from the sorted array, Array.find will return the first matching result :
var arrObj = [
{ id: 1, startDate: "2019-10-09" },
{ id: 1, startDate: "2019-10-05" },
{ id: 1, startDate: "2019-09-30" },
{ id: 2, startDate: "2018-08-05" },
{ id: 2, startDate: "2018-09-05" }
];
// Sort by date
var sorted = arrObj.sort((a, b) => new Date(b.startDate) - new Date(a.startDate));
// dedupe the array of ids
var ids = [...new Set(sorted.map(o => o.id))];
// replace the ids with original objects
var result = ids.map(id => sorted.find(o => o.id === id));
console.log(result);

Categories