I want to add an object and delete two objects in a function
const old1 = [
{item: "apple", number: 13}
]
const old2 = [
{item: "apple", number: 13},
{item: "banana", number: 11},
{item: "orange", number: 13}
]
First, I want to add an object in the array
const add = {item: "pear", number: 3}
Then I want to check if the array has these elements, if yes, then remove them. Here I want to remove anything "banana" and "orange"
const new2 =[
{item: "pear", number: 3},
{item: "apple", number: 13}
]
I tried old1.unshift to add an element.
I also tried old2.splice(0,2) to remove elements but it is based of the index order. I should check the item property and remove the relative one.
You can use Array.push to add the element:
old1.push({item: "pear", number: 3});
And for removing based on a condition - you could put the values you want to remove in an array, then run an Array.filter
let itemsToRemove = ["banana", "orange"]
let filteredItems = old2.filter(o => !itemsToRemove.includes(o.item));
For an array of objects I use code similar to this to add/update them.
addUpdateItem(item, arr) {
let ind = arr.map(i => i.id).indexOf(item.id) //find the position of element if exists
if(ind != -1) { //this means the item was found in the array
//normally I would want to update the item if it existed
Object.assign(arr[ind], item) //update the item
//but if you wanted to remove the item instead
arr.splice(ind, 1) //removes the item
} else {
arr.push(item)
}
}
Related
Let's say I have a data set that looks like below:
const fruits = [
{ fruit: "banana", price: 100 },
{ type: "apple", price: 200 },
{ item: "grape", price: 150 },
// And so on...
];
const rotten = ["banana", "orange", /* And so on...*/];
I need to filter out elements that contain one of the values in 'rotten' array from 'fruits' array.
Some characteristics:
The key names in the 'fruits' objects are inconsistent. We just know that the corresponding string values are there. I know it is suboptimal but fixing this is sadly not a near-term option.
The actual length of 'fruits' is ~100 and that of 'rotten' is ~10. So this is not a small dataset. (There is a context for saying this...)
I already tried going through each element in 'rotten' and use Object.values(obj).includes() for each element in 'fruits' to eventually create a filtered array, but considering the size of the dataset, this is expensive and I will need a better way to handle this.
What might be a better way to do this? Any suggestions? Thanks a lot in advance!
It is unusual (and not practical) that your input objects all use different properties for storing the same information (fruit, type, item...). So, you should really improve the source of this data.
But given it is like this, you'll have to scan each property of each object and compare it with the rotten fruit names. The latter can be put in a Set, which will reduce the time complexity of the search:
const fruits = [
{ fruit: "banana", price: 100 },
{ type: "apple", price: 200 },
{ item: "grape", price: 150 },
];
const rotten = ["banana", "orange"];
let rottenSet = new Set(rotten);
let result = fruits.filter(item =>
!Object.values(item).some(value => rottenSet.has(value))
);
console.log(result);
You can try this.
const fruits = [
{ fruit: "banana", price: 100 },
{ type: "apple", price: 200 },
{ item: "grape", price: 150 }
];
const rotten = ["banana", "orange"];
const stringfyFruites = JSON.stringify(fruits);
let filterdArray = [];
rotten.forEach((value) => {
const regexstr = '{[\\w":,\\s]+' + value + '[\\w":,\\s]+}';
const matchedobject = stringfyFruites
.match(new RegExp(regexstr, "gm"))
?.map((a) => JSON.parse(a));
if (matchedobject?.length) filterdArray = [...filterdArray, ...matchedobject];
});
If given an array of ids [1,2,3,4,5]
And an object array:
[{animal:tiger, id:1}, {animal:"fish", id:2}]
What would be the suggested way to return 'tiger, fish'. Would that be through using .map or would a for loop be better for constructing the sentence?
What you need is just go through the list of ids and find corresponding animal in the animals list.
Note, that in case animals list is not expected to store all the animals and some of them are missing, you will need to add additional filter step to be sure that no undefined values appear on the last map step.
const ids = [1,5,2,4,3,6]; // added 6 which is missing in animals
const animals = [
{name:'Tiger',id:1},
{name:'Horse',id:2},
{name:'Mouse',id:3},
{name:'Elephant',id:4},
{name:'Cat',id:5}
];
const result = ids
.map(id => animals.find(a => a.id === id))
.filter(Boolean) // this will exclude undefined
.map(a => a.name)
.join(',');
console.log(result);
var ids = [1,2,3,4,5];
var objects = [{ animal:"tiger", id: 1 }, { animal: "fish", id: 2 }];
objects.map(function(o) { if(ids.includes(o.id)) return o.animal }).join();
I'm guessing you only want the animal names who's id appears in your array. If so, you could filter the array of objects first, followed by a map and a join.
let idarr = [1, 2, 3, 4];
let objarr = [{
animal: "tiger",
id: 1
}, {
animal: "fish",
id: 2
}];
console.log(objarr.filter(x => idarr.includes(x.id)).map(x => x.animal).join(', '))
I suggest two options, depending on your data & use cases.
1. map + find if the animal kingdoms are not too many to loop through.
const animals = [
{animal:tiger, id:1},
{animal:"fish", id:2}
]
const ids = [1,2,3,4,5];
const names = ids.map(id =>
animals.find(animal => animal.id === id));
2. convert animals array to object first, for easier frequent access later. One upfront loop, then easier to access by id later.
const animals = [
{animal: "tiger", id:1},
{animal: "fish", id:2}
]
/*
Convert
[{animal:tiger, id:1}, {animal:"fish", id:2}]
to
{
1: { animal: "tiger", id: 1 },
2: { animal: "fish", id: 2 },
}
*/
const animalsObj = animals.reduce((acc, animal) => {
return {
...acc,
[animal.id]: animal,
}
}, {});
const ids = [1,2,3,4,5];
const names = ids.map(id => animalsObj[id].animal)
I have a JSON response as below:
[{
"id": 1,
"food": {
"fruits": ["Banana", "Orange", "Apple", "Mango"],
"veggies": ["greens", "peppers", "carrot", "potatoes"],
}
},
{
"id": 2,
"food": {
"fruits": ["grapes", "berries", "peach", "pears"],
"veggies": ["cabbage", "spinach"],
"dairy": ["nutmilk", "goatmilk"]
}
}
]
Now i want to merge the Arrays each "id" (1,2 in example) into string ( ; delimited) like below:
id_1 = Banana;Orange;Apple;Mango;greens;peppers;carrot;potatoes
// observer "id_2" has additional array - "dairy"
id_2 = grapes;berries;peach;pears;cabbage;spinach;nutmilk;goatmilk
The key's are dynamic so for some records there are 2 arrays and for some records it can be 3 or 4 and may be 1.
I tried using react/Java Script Array.concat(), but i am not sure how to do it dynamically. Please help me. Thank you.
This is doable easily using Object.values().flat().join(';') demonstrated below:
let arr=[{"id":1,"food":{"fruits":["Banana","Orange","Apple","Mango"],"veggies":["greens","peppers","carrot","potatoes"],}},{"id":2,"food":{"fruits":["grapes","berries","peach","pears"],"veggies":["cabbage","spinach"],"dairy":["nutmilk","goatmilk"]}}];
const result = arr.map(({id,food}) => ({id, food: Object.values(food).flat().join(';')}));
console.log(result);
You may easily restructure the output by simply changing it to e.g. ["id_"+id]: Object.values(...)
First flatten using map, flat and join. Then convert the resulting array of objects to a single object using assign.
var db = [{"id": 1,"food": {"fruits": ["Banana", "Orange", "Apple", "Mango"], "veggies": ["greens","peppers","carrot","potatoes"], }},{"id" : 2,"food": {"fruits": ["grapes", "berries", "peach", "pears" ], "veggies": ["cabbage","spinach"], "dairy": ["nutmilk","goatmilk"]}}];
var flat = db.map(
({id, food}) => ({[`id_${id}`]: Object.values(food).flat().join(';')})
);
var result = Object.assign(...flat);
console.log(result);
This is really two problems: looping through an array of objects to combine them into one object, and looping through an object to concat all of its array.
Tackling the second one first, something like this would work:
const concatArraysInObject = obj =>
Object.values(obj).reduce((result, arr) => result.concat(arr), []);
const input = { a: [1,2,3], b: [4,5,6], c: [7,8,9] };
const output = concatArraysInObject(input);
console.log(output);
Object.values() will give you an array of all arrays in an object.
The reduce() function takes a two parameters: a function and initial value.
The function should also take (at least) 2 parameters: the result of the last call (or initial value) and the current value in the array.
It'll call the function once for each element in the array.
Now, with that solved, we can tackle the first problem.
For this, we can also use reduce() as well, and we'll construct our combined object on each call.
const concatArraysInObject = (obj) =>
Object.values(obj).reduce((result, arr) => result.concat(arr), []);
const mergeObjectsInArray = (arr, dataKey) =>
arr.reduce((result, obj) => ({ ...result, [obj.id]: concatArraysInObject(obj[dataKey]) }), {});
const input = [
{ id: 'A', data: { a: [1,2,3], b: [4,5,6] } },
{ id: 'B', data: { c: [7,8,9], d: [10,11,12] } }
];
const output = mergeObjectsInArray(input, 'data');
console.log(output);
An important note of warning: object key order is NOT guaranteed in JavaScript. While 99% of the time they will be in the order you expect, this is not a guarantee, so if you depend on the order of the keys for the order of the array (if order matters), you'll want to change your input structure. If order doesn't matter, it is probably fine how it is.
Try this using basic for loop. Inside you will compute key dynamically and value being flattened array of Object.values of the iterating object.
var input = [{
id: 1,
food: {
fruits: ["Banana", "Orange", "Apple", "Mango"],
veggies: ["greens", "peppers", "carrot", "potatoes"]
}
},
{
id: 2,
food: {
fruits: ["grapes", "berries", "peach", "pears"],
veggies: ["cabbage", "spinach"],
dairy: ["nutmilk", "goatmilk"]
}
}
];
var temp = [];
for (var i = 0; i < input.length; i++) {
temp.push({
[`id_${input[i].id}`]: Object.values(input[i].food)
.flat(1)
.join(";")
});
}
console.log(temp); // this gives you an array
console.log(Object.assign(...temp));// in case you require one single object
I have an array of strings which are tags of blog posts from database.
This is the example end result of a query :
["apple","banana", "apple", "orange","grapes","mango","banana"];
I need to know how many times a string is repeated in that array so I can build a sort of tag cloud.
Final end result should look like: [{name:"apple",count:2}, {name:"banana", count:2}, {name: "orange",count:1} ...];
I am using lodash in my project and would like to use it if possible. plain javascript is also fine.
You can use groupBy to do the heavy lifting then use map to format the result to your liking:
const data = ["apple", "banana", "apple", "orange", "grapes", "mango", "banana"];
const result = _.values(_.groupBy(data)).map(d => ({name: d[0], count: d.length}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Use reduce and map
var input = ["apple","banana", "apple", "orange","grapes","mango","banana"];
var map = input.reduce( (a,c) => ( a[c] = a[c] || 0, a[c]++, a ) ,{});
var output = Object.keys( map ).map( s => ({name: s, count:map[s]}) );
Demo
var input = ["apple", "banana", "apple", "orange", "grapes", "mango", "banana"];
var map = input.reduce((a, c) => (a[c] = a[c] || 0, a[c]++, a), {});
var output = Object.keys(map).map(s => ({
name: s,
count: map[s]
}));
console.log(output);
Create a map, mapping name to count. Loop over the list, for each item, if its' in the map, increment it's count, else set its count to one.
if (tag in map) { map[tag] += 1 }
else { map[tag] = 1 }
Then you can iterate of the map and convert it to a list of objects.
To count use _.countBy(), then transform to requested form, by using _.entries(), and mapping the tuples to objects:
const data = ["apple", "banana", "apple", "orange", "grapes", "mango", "banana"];
const result = _.entries(_.countBy(data)).map(([name, count]) => ({ name, count }));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
I have an array of React objects and I want to sort them based on value of one of their props.
var arr=[];
arr[0] = <Fruit name="orange" count={10}/>
arr[1] = <Fruit name"apple" count={5}/>
Is there built in React function that I can use to sort this array in ascending order of fruit count?
React does not have a built in function to handle this (that I know of), but you could use something like lodash to achieve what you want. I would also suggest that you change the structure of your data slightly. Have a look at the example below.
// your data comes in like this
var arr = [
{name: "orange", count: 10},
{name: "apple", count: 5},
{name: "lemon", count: 11},
{name: "grape", count: 2}
];
// order by ascending
var newArr = _.sortBy(arr, 'count', function(n) {
return Math.sin(n);
});
// create your components
var fruits = newArr.map(function(fruit) {
return(
<Fruit name={fruit.name} count={fruit.count} />
);
});
Here is a fiddle to illustrate the sorting function input and output
If you want to sort depending on multiple fields:- //using lodash
sortingFunction(arrayTobeSorted) {
let sortedResults = sortBy(arrayTobeSorted, function(e) {
return [e.field1.trim().toUpperCase(), e.field2.trim().toUpperCase()];
});