find value (and key) of an object in array (JS) - javascript

I am writing a function that will iterate through an of objects to find if key:value pair exists and if so, it adds into another array (in case there are multiple matches)
The array contains objects. The function takes as argument what key and value you're looking for and then iterates through array till it finds it. As you can see, key is a variable then and my problem is I am not sure how to access object property when referring to as a variable value.
for (let i = 0; i < arr.length; i++) {
if (arr[i].[key] == value) {
result.push(arr[i]);
}
}
I thought maybe putting it in [key] would help, but I was obviously wrong. I tried googling how to do it, but I guess i can't put it in words right .

You are confusing dot notation with bracket notation.
Remove the .; arr[i].[key] == value1 should be arr[i][key] == value.
const arr = [{
'a': 'b'
}]
key = 'a'
value = 'b'
const result = []
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] == value) {
result.push(arr[i]);
}
}
console.log(result)
You can simplify the code by using filter:
const arr = [{
'a': 'b'
}]
key = 'a'
value = 'b'
const result = arr.filter(e => e[key] == value)
console.log(result)

You can use ES6+ and ternary true ( && == only true action )
const arr = [{
a: 'b'
}];
const key = 'a';
const value = 'b';
const result = [];
for (const item of arr) {
(item[key] === value) && result.push(item)
};
console.log(result);
You can simplify the code by using filter:
const arr = [{
a: 'b'
}];
const key = 'a';
const value = 'b';
const result = [];
for( const item of arr ) {
( item[key] === value ) && result.push( item )
};
console.log( result );

use Array.prototype.filter()
You should know upfront what exact property name you're willing to reference to:
const arr = [
{name:"Evan", age:28},
{name:"John", age:23},
{name:"Anne", age:28},
];
const searchProp = "age";
const searchValue = 28;
const result = arr.filter((user) => user[searchProp] === searchValue);
console.log(result)

You are almost there, just get rid of the extra . between [i] and [key]:
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] == value) {
result.push(arr[i]);
}
}
However, there would be a simpler and more straight-forward way, using filter:
const result = arr.filter(obj => obj[key] == value)
Example:
const arr = [
{ a: 1, b: 1 },
{ a: 1, b: 2 },
{ a: 2, b: 1 },
{ a: 2, b: 2 }
]
const key = 'b'
const value = 1
const result = arr.filter(obj => obj[key] == value)
console.log(result)
// Output: [{ a: 1, b: 1 }, { a: 2, b: 1 }]

Related

How to pass array values as an object prop dynamicly?

I need to treat array values as props of object. For example:
let arr = ['masa_icerik', 'urunler', 0, 'urun_adet'];
let obj = {
"_id": "5c13bd566704aa5e372dddcf",
"masa_id": 3,
"masa_numara": 3,
"masa_magaza": 1,
"masa_icon": "kola",
"masa_adi": "salon 3",
"masa_durum": 1,
"masa_icerik": {
"adisyon": "J1554745811908",
"urunler": [{
"urun_adet": 14,
"urun_fiyat": 3,
"urun_id": "5c16686b93d7b79ae6367864",
"urun_odenen": 0
}, {
"urun_adet": 1,
"urun_fiyat": 5,
"urun_id": "5c16686b93d7b79ae6367865",
"urun_odenen": 0
}]
},
"masa_acilis": "2019-04-08T17:50:12.052Z",
"masa_acan": "5c1eda01d1f4773110dd6ada"
};
I have an array and an object like above and I want to do something like this:
let res;
arr.forEach(elem => {
res = obj[elem];
});
and after that I need to get something like :
obj['masa_icerik']['urunler'][0]['urun_adet']
The number of the values is dynamic from server. Thats why i need something like this. Is there any way to do that? I need to change that property and return the changed obj.
You can use forEach loop to loop thru the array and store it to a temp variable. If all elements exist, it will change the value.
let arr = ['a', 'b', 'c'];
let obj = {'a':{'b':{'c':1}}};
let newValue = "NEW VALUE";
let temp = obj;
arr.forEach((o, i) => {
if (i < arr.length - 1) temp = temp[o] || null;
else if (temp !== null && typeof temp === "object" ) temp[o] = newValue;
});
console.log(obj);
If there are multiple multiple object properties missing in the last part of the array.
let arr = ['a', 'b', 'c', 'd'];
let obj = {'a': {'b': {}}};
let newValue = "NEW VALUE";
let temp = obj;
arr.forEach((o, i) => {
if (i < arr.length - 1) {
if (!temp[o]) temp[o] = {[arr[i + 1]]: {}};
temp = temp[o];
} else if (temp !== null && typeof temp === "object") temp[o] = newValue;
});
console.log(obj);
You can use references
Here idea is
Initialize val with object reference
Loop through array and keep setting new reference to val
let arr = ['a','b','c'];
let obj = {'a':{'b':{'c':1}}};
let getMeValue = (arr) => {
let val=obj;
arr.forEach(e => val = val && val[e] )
return val
}
console.log(getMeValue(arr))
console.log(getMeValue([1,2,3]))
UPDATE: I want to change values
let arr = ['a','b','c'];
let obj = {'a':{'b':{'c':1}}};
let getMeValue = (arr) => {
let val = obj
arr.forEach((e,i) => {
if(i === arr.length-1 && val){
val[e] = 5
}
else {
val = val && val[e]
}
})
return obj
}
console.log(getMeValue(arr))
I am not fully understanding where you are getting the new values from but I think this will get you on the right track.
let newObj = {};
arr.map(each => {
newObj[each] = "new value";
})
console.log(newObj);
I'm not sure about your requirment here, I guess you want the below:
let func = (arr, value)=>{
r = {};
r[arr[arr.length-1]] = value;
for(let i = arr.length-2; i>=0; i--){
obj = {};
obj[arr[i]] = r;
r = obj;
}
return r;
}
console.log(func(['a', 'b', 'c'], 1));

Javascript converting 2 string arrays to map

I have two string arrays keys and values:
let keys = [a,b,c,d]
let values = [1,2,3,4]
How to convert them into a map?
Expected output would be:
{a: "1", b: "2", c: "3", d: "4"}
you can use Map in ES6
var myMap = new Map();
// setting the values
myMap.set('key1', 'value1');
myMap.set('key2', 'value2');
myMap.set('key3', 'value3');
your answer :
for (let i = 0; i < keys.length; i++) {
myMap.set(keys[i], values[i]);
}
Firstly create an object. Then loop through your array and add the keys and values to the object.
let keys = ['a','b','c','d'];
let values = [1,2,3,4];
let obj = {};
keys.forEach((key, index) => {
obj[key] = values[index]
});
console.log(obj);
You can use array reduce on any of the array and use index to retrieve value from another array
let keys = ['a', 'b', 'c', 'd'];
let values = [1, 2, 3, 4];
let k = keys.reduce((acc, curr, index) => {
acc[curr] = values[index]
return acc;
}, {});
console.log(k)
First of all, you need to declare your string arrays properly.
let keys = ['a', 'b', 'c', 'd'];
let values = ['1', '2', '3', '4'];
var zip = (target, ...arr) => {
if (target == null) throw Error('Target is undefined');
if (arr[0] == null || arr[1] == null) throw Error('Lists must not be null');
if (arr[0].length !== arr[1].length) throw Error('Lists must match in length');
if (Array.isArray(target)) {
arr[0].forEach((x, i) => target.push([arr[0][i], arr[1][i]]));
} else if (typeof target === 'object') {
arr[0].forEach((x, i) => target[arr[0][i]] = arr[1][i]);
} else {
throw Error('Unsupported target type');
}
return target;
}
var zipObj = (...arr) => zip.call(null, {}, ...arr);
var zipArr = (...arr) => zip.call(null, [], ...arr);
//console.log(zip({}, keys, values));
console.log(zipObj(keys, values)); // Zip object
//console.log(zip([], keys, values));
console.log(zipArr(keys, values)); // Zip array
.as-console-wrapper { top: 0; max-height: 100% !important; }
When using lodash this is a one-liner:
_.zipObject(keys,values)
This should do the trick:
let keys = ['a','b','c','d']
let values = [1,2,3,4]
let mapped = keys.reduce((accumulator, current, index) => {
accumulator[current] = values[index];
return accumulator;
}, {});
console.log(mapped)
// Result should be:
{a: 1, b: 2, c: 3, d: 4}
Reduce is a powerful method that can be used for all sorts of tasks.
Here we're "reducing" the given values of keys into an object where keys are the key and values are the correlating values.
The first parameter in reduce is a callback function that you need to pass along at minimum accumulator and current variables (can have different names); the other parameters are index and array which represent the current index of the iteration and the original array that is being iterated.
The second parameter is the initial value of the accumulator; by default it will be the first current value but in our case we set it to {} so we can treat it as an object.
I hope this helps!

JavaScript ES6 - count duplicates to an Array of objects

I'm creating for my list of products a filter to count all producers and display like this:
Apple (3)
I eliminated the duplicates from array: ["Apple","Apple","Apple"] I used this link:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
But my problem is that I want to count these elements from array and display them in an Array of Objects cause i need to iterate it later.
From this Array of Apples above i need result: [{"Apple": 3},{...},{...}]
I was trying to do this but it returns me object and I can't iterate after it:
How to count duplicate value in an array in javascript
I need an Array of Objects it's not duplicated
I'm using Angular 4.
My code:
component.ts
async ngOnInit() {
this.cart$ = await this.cartService.getCart();
this.subscription = this.productService.getAll().subscribe(products => {
this.category = products.filter(
products => products.category == this.name
);
this.filters();
});
}
filters() {
this.category2 = this.category.map(value => value.producer);
this.filteredArray = this.eliminateDuplicates(this.category2);
console.log(this.filteredArray);
}
eliminateDuplicates(arr) {
let i,
len = arr.length,
out = [],
obj = {};
for (i = 0; i < len; i++) {
obj[arr[i]] = 0;
}
for (i in obj) {
out.push(i);
}
return out;
}
component.html
<div *ngFor="let f of filteredArray">
{{f}}
</div>
You can use reduce to summarize the array and map for form the desired output
let obj = ["Apple", "Apple", "Apple", "Orange"];
let result = Object.values(obj.reduce((c, v) => {
c[v] = c[v] || [v, 0];
c[v][1]++;
return c;
},{})).map(o=>({[o[0]] : o[1]}));
console.log(result);
Here:
const array = ["a", "a", "b"]
const result = { }
for (let i = 0; i < array.length; i++) {
result[array[i]] = (result[array[i]] || 0) + 1
}
Object.keys(result).map(key => ({ [key]: result[key] }))
That last line is the key for
I was trying to do this but it returns me object
you can simply do it by using Lodash countBy function
filters() {
this.category2 = this.category.map(value => value.producer);
this.filteredArray = _.countBy(this.category2);
console.log(this.filteredArray);
// Object {Apple: 3, Orange: 1}
}
You can simply do it by using array.reduce() method
const votes = ['Yes', 'Yes', 'Yes', 'No', 'No', 'Absent'];
const result = votes.reduce((prevValue, vote) => {
if (prevValue[vote]) {
prevValue[vote]++;
} else {
prevValue[vote] = 1;
}
return prevValue;
}, {});
console.log(result);
Output : { Yes: 3, No: 2, Absent: 1 }

How to find unique key with desire array value?

I want to get unique p which c values contain all desire_c value !
So here object's p:1 has c value like 1,2,3 . That is match desire_c array value , so I want to get
{p:1} as final result !
Here I am looping in using for loop :(
var object = [{p:1,c:1},{p:1,c:2},{p:1,c:3},{p:2,c:1},{p:3,c:3}];
var desire_c = [1,2,3];
var helper = {};
for(var o in object) {
var current = object[o];
if(typeof helper[current.p] != 'object') {
helper[current.p] = {};
}
helper[current.p][current.c] = null;
}
for(var c of helper) {
for(var d in desire_c) {
c[desire_c[d]]
}
}
You could take a map for p and a set for each c value and check then if all wanted values are in a set.
var object = [{ p: 1, c: 1 }, { p: 1, c: 2 }, { p: 1, c: 3 }, { p: 2, c: 1 }, { p: 3, c: 3 }],
desire_c = [1, 2, 3],
map = new Map,
result;
object.forEach(({ p, c }) => map.has(p) ? map.get(p).add(c) : map.set(p, new Set([c])));
result = [...map.keys()].filter(p => desire_c.every(c => map.get(p).has(c)));
console.log(result);
You can use this auxiliary function to find the unique value:
function findKey(objects, desire){
const map = {}; // Creates a new object to map all keys to all their values, instead of having an array of objects
objects.forEach(obj => {
map[obj.p] = map[obj.p] || []; // Ensures the key has an array of values before pushing a new value
map[obj.p].push(obj.c);
});
return Object.keys(map).find(key => desire.every(des => map[key].includes(des))); // Tries to find a key that contains all desired values
}
Then, just call it like that:
findKey(object, desire_c); // Returns 1 for your example
Please check below code.
var desire_c = [1,2,3];
var data=[{p:1,c:1},{p:1,c:2},{p:1,c:3},{p:2,c:1},{p:3,c:3}];;
var helper = {},element = "p";
for (var i = 0; i < data.length; i++) {
if (!helper[data[i][element]])
helper[data[i][element]] = [];
helper[data[i][element]].push(data[i]["c"]);
};
for (key in helper) {
if (helper.hasOwnProperty(key)) {
if (helper[key].length){
var arr=helper[key];
if(JSON.stringify(arr)==JSON.stringify(desire_c))
{
console.log({"p":key});
}
}
}
}
const hash = {};
for(const {p, c} of object){
if(!hash[p]){
hash[p] = desire_c;
}
hash[p] = hash[p].filter(n => n !== c);
}
const result = [];
for(const [key, val] of Object.entries(hash))
if(!val.length) result.push(key);
This just goes over every p and c in the array, and removes c from the array stored inside the hashtable under p. This array is initialized to your wanted array, so if all elements are removed from it (!val.length) the corresponding key is the one we are looking for.

What is the most efficent way to filter an object with an array of arrays?

I'm trying to filter an Object by an array of arrays, getting back an array of objects.
Like this:
let obj =
{
"a.1":1,
"a.2":2,
"b.1":3,
"b.2":4,
"c.1":5,
"c.2":6
}
let array =
[
["a.1","b.1"],
["a"],
["b","c.1"]
]
let expectedResult =
[
{
"a.1":1,
"b.1":3,
},
{
"a.1":1,
"a.2":2,
},
{
"b.1":3,
"b.2":4,
"c.1":5
},
]
// this is what I came up with
const filterObjectByArray = (obj, arr) =>
Object.keys(obj)
.filter(ch => {
for (var index = 0; index < arr.length; index++)
if (ch.startsWith(arr[index]))
return true;
})
.reduce((ret, key) =>{
ret[key] = obj[key]
return ret
},{})
let result = array.map(arr => filterObjectByArray(obj, arr))
//kind of deepEqual
console.log(JSON.stringify(expectedResult) == JSON.stringify(result))
Is there a easier or more convenient way to do that? I need to do this operation quite often and my object will be up to couple hundreds entries big, so I see a potential bottleneck here.
I would create a one type mapping of the "base" (the letter) to the "real" keys, and then use it to translate the letter to the real keys when create the object.
const obj = {
"a.1": 1,
"a.2": 2,
"b.1": 3,
"b.2": 4,
"c.1": 5,
"c.2": 6
};
const array = [
["a.1", "b.1"],
["a"],
["b", "c.1"]
];
const getBaseKey = (key) => key.match(/^[a-z]+/)[0]; // get the base of the key - the letter. If it's only one letter, you can use key[0]
/** create a one time map of keys by their base **/
const oobjKeysMap = Object.keys(obj).reduce((map, key) => {
const baseKey = getBaseKey(key);
const curr = map.get(baseKey) || [];
curr.push(key);
return map.set(baseKey, curr);
}, new Map());
const result = array.map((sub) => // iterate the array
[].concat(...sub.map((k) => k in obj ? k : oobjKeysMap.get(getBaseKey(k)))) // create the least of "real" keys
.reduce((ret, key) => { // create the object
ret[key] = obj[key];
return ret;
}, {})
);
console.log(result);

Categories