Get all Indexes of Objects in Array - from Array in Object - javascript

i´m struggling with a Array in a Object stored in a Array with Objects from which I want return all Indicies.
Function to generate Object looks like this:
const addArray = function(a, b) {
const object = {
name: a,
rooms: b
};
testArray.push(object);
};
What I want to achieve is to cycle through the "testArray" and return every Index from the Object where the Array Rooms contains "Office" for example.
I´ve already tried to use a function like this but I don´t seem to be able to get the right Syntax for the Array in the Object:
function getAllIndexes(arr, val) {
var indexes = [], i = -1;
while ((i = arr.rooms.indexOf(val, i+1)) != -1){
indexes.push(i);
}
return indexes;
};
Thanks in advance!
Edit:
Additional Informations to Data:
A Object with data filled would look like this:
const device = {
name: "TV",
rooms: ["Living Room", "Bedroom"]
};
After generating Objects like this I push them to an array witch only contains this objects (see function addArray)

You can use Array.flatMap() to map each value of the array at matches val to it's index, and the rest to empty array, which will be removed by the flatMap:
const getAllIndexes =(arr, val) => arr.flatMap((v, i) => v === val ? i : [])
const arr = [1, 2, 3, 1, 2, 1, 1, 2]
const result = getAllIndexes(arr, 1)
console.log(result)
Using your array of objects, you'll need to compare a value, or check if an object meets some condition. It's better in this case to replace val with a predicate function:
const getAllIndexes =(arr, pred) => arr.flatMap((v, i) => pred(v) ? i : [])
const arr = [{ rooms: [1, 2, 3] }, { rooms: [2, 1, 1] }, { rooms: [3, 2, 2] }, { rooms: [1, 2, 1] }]
const result = getAllIndexes(arr, o => o.rooms.includes(1))
console.log(result)

Try using Array.prototype.map and Array.prototype.filter
function getAllIndexes(arr, val) {
return arr.map(i=> {
let room = i.rooms;
return room.indexOf(val);
}).filter(a=>{
a != -1;
});
};

You could destructure rooms from the device and get the index, if the wanted value is found.
const
room = 'Office',
indices = array.flatMap(({ rooms }, i) => rooms.includes(room) ? i : []);
The above code features a former solution from me with hacking Array#flatMap.

Related

How to iterate through map and push keys with similar values into the same array?

I've got javascript map with structure like this:
let map = {3 => 1,
15 => 2,
0 => 2,
8 => 3,
9 => 3}
I need to receive the arrays of keys, and keys with similar values should be in the same array.
[[3], [15,0],[8,9]]
This is what I've tried:
let answers = [];
let currentVal = 1;
map.forEach((value, key)=>{
let subArr = [];
if(value === currentVal){
subArr.push(key);
answers.push(subArr);
currentVal++;
}
});
return answers;
And it returns [[3], [15], [8]]
I assume your map is an object, not map for readability reasons, but if u are using Map there you can change methods to get elements but main idea you can see below:
const data = {
3: 1,
15: 2,
0: 2,
8: 3,
9: 3
};
const customData = Object.entries(data).reduce((acc, [key, value]) => {
if (value in acc) {
acc[value].push(key);
} else {
acc[value] = [key];
}
return acc;
}, {});
const finalArray = Object.values(customData);
console.log(finalArray);
Edit with Map() example:
const data = new Map([
[3, 1],
[15, 2],
[0, 2],
[8, 3],
[9, 3]
]);
const customData = Array.from(data).reduce((acc, [key, value]) => {
if (value in acc) {
acc[value].push(key);
} else {
acc[value] = [key];
}
return acc;
}, {});
const finalArray = Object.values(customData);
console.log(finalArray);
You could use Object.entries and destructuring key, value but I change their place as value, key to match the data structure map provided by OP :
let map = { 3: 1, 15: 2, 0: 2, 8: 3, 9: 3 };
const arr = [];
for (const [value, key] of Object.entries(map)) {
if (arr[key]) {
arr[key].push(value);
} else {
arr[key] = [value];
}
}
console.log(arr.filter(Boolean)); // [[3], [15,0],[8,9]]
NOTE arr.filter(Boolean) to remove falsy (empty) values from array since index 0 have no array inside of it!
Your map is not a valid one. Hence, I am creating it by using Map instance. You can have a look in this official documentation of Map Object.
Live Demo :
// Creating a map object by using Map instance
const map = new Map();
// Setting the key, values in map object.
map.set(3, 1)
map.set(15, 2)
map.set(0, 2)
map.set(8, 3)
map.set(9, 3)
// Declaring an empty array which will store the result.
const arr = [];
// Iterate over a map object and assign the keys of map object into an 'arr'.
for (const [key, value] of map) {
(arr[value]) ? arr[value].push(key) : arr[value] = [key];
}
// Output
console.log(arr.filter(Boolean));

How to change from array of values to array of objects?

I got data like this:
{"my_data":{"labels":[1,2,3,...], "idx":["idx1", "idx2", ...]}}
But I need it like this:
["my_data":{"labels":1, "idx": "idx1"},{"labels":2, "idx": "idx2"},... ]
I tried to loop like this to change the format:
var arr = [];
for (let [key, value] of Object.entries(my_data)) {
arr.push({[key]:value});
}
console.log(key, value);
But the result is a format I can not use with ag-grid
labels: [1,2,...]
idx: [idx1, idx2,...]
One way you can approach this is by using the map method like in the following example:
const temp = { my_data: { labels: [1, 2, 3], idx: ["idx1", "idx2", "idx3"] } };
const result = temp.my_data.labels.map((label, index) => {
const idx = temp.my_data.idx[index];
return {
label,
idx
};
});
console.log(result)
This way, you're mapping through labels then extracting the value for idx based on the index of the label.

Pick the array by property name from another array

I have an array like that
I want to pick the array item by property name, I am using lodash for that:
const result = _.map(this.thing, _.property('groups')).filter(x => x !== undefined);
But I am getting array of arrays as result
What I need is just single selected property array.
Any idea how to achieve that?
Try this>>>
var a = [{"p1":[3,4]},{"p2":[6,7]}];
function getArr(arr,key){
var res = [];
for(var v of arr){
if(v[key]!=undefined){
res = v[key];break;
}
};
return res;
}
console.log(getArr(a,"p1"));
If you can use ES6/ES7, you can rely on Object.keys and Object.values to access to the key (that is the property name) and the value (the array you want to get):
var arr = [
{ groups: [1, 2 ] },
{ category: [1, 2, 3 ] },
{ subCategory: [1, 2, 3, 4 ] }
];
function pickArray(propertyName) {
var element = arr.find(el => Object.keys(el)[0] === propertyName)
return element ? Object.values(element)[0] : null;
}
var res = pickArray('category');
console.log(res);
const output
= (Array.from(arr, (obj) => obj['product'], 'product')
.filter(x => typeof x !== 'undefined'))[0];
Try this:
const arr = [ {'groups': ['item1','item2']},
{'categories':['x','y']}
]
var ouptut= arr.find(item=> {
return item[Object.keys(item).find(key=>key === 'groups')]
})
console.log(ouptut)

Spread syntax not working as expected with array of objects

I have a react component where I am trying to spread objects into the state in the constructor.
constructor() {
super()
const shapesArray = [1, 2, 3]
let renderStates = shapesArray.map((el, i) => {
return {['shape'+i]: 'black'}
})
this.state = { ...renderStates }
console.log(this.state)
}
I want to access the colors by doing this.state.shape0,
but when I console log this.state, I get this:
instead of Object {shape0: "black", shape1: "black", shape2: "black"}.
What am I doing wrong here?
That is because you are spreading an Array into an Object. Arrays are actually objects with (usually) sequential integral strings as their keys. These keys are the indices of the array.
As shown below, map takes an array and produces another array
const shapesArray = [1, 2, 3];
const renderStates = shapesArray.map((el, i) => {
return {
['shape' + i]: 'black'
}
});
console.log(renderStates);
When spreading into an Object, the value of each own enumerable property in the source Object is added to the target under its respective key. Since the keys of an array are its indices you end up with an Object with a property for each element of the Array. The name of each property is its index in the array.
To achieve what you want, you can use Array.prototype.reduce to build an object from the array with the names created in the mapping process.
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.map((el, i) => {
return {
['shape' + i]: 'black'
}
})
.reduce((o, element) => {
Object.keys(element).forEach(key => o[key] = element[key]);
return o;
}, {});
console.log(renderStates);
Of course this itself can be written more elegantly by spreading the object inside of reduce.
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.map((el, i) => {
return {
['shape' + i]: 'black'
}
})
.reduce((o, element) => ({...o, ...element}), {});
console.log(renderStates);
As an optimization to aluan-haddad's answer, reduce can handle the logic that was in map
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.reduce((acc, _, i) => ({
...acc,
['shape' + i]: 'black',
}), {});
console.log(renderStates);
renderStates is an array which has integer properties starting from 0 or the array indices if you want to be specific, so {...renderStates} will take each index, and create a mapping from this index to the value corresponding to that index, to achieve what you are looking for, you need to reduce your renderStates array to an object like so
let renderStates = shapesArray.map((el, i) => {
return {['shape'+i]: 'black'}
}).reduce((resultObj, currentShape,index) => resultObj['shape'+index] = currentShape['shape'+index]), { });
renderStates is now an object, and you can spread it and it will produce the result you want
No need to iterate twice over array. Use reduce:
const shapesArray = [1, 2, 3];
const renderStates = shapesArray.reduce((accumulator, i) => {
accumulator['shape' + i] = 'black';
return accumulator;
}, {});
console.log(renderStates);

Underscore.js _.reduce() to return objects

I'm attempting to create a list of how many stores carry a given item from an array of stores. Individual objects in the stores array can contain a bunch of different properties (name, location, etc.), but I'm just looking to pick out the inventory (an array of item types they carry, not actual stock numbers -- looks like ['hammers', 'wrenches', 'screw drivers'), and create an object with each item as a property containing a count.
//simplified stores array for reference
stores = [
{ name: "Al's Hardware", inventory: ['hammers', 'wrenches'] },
{ name: "House Depot", inventory: ['wrenches', 'hammers', 'screw drivers'] },
{ name: "Grove Hardware", inventory: ['wrenches', 'screw drivers'] }
];
var itemCount = _(stores).chain()
.map(store => store.inventory)
.flatten()
.reduce((list, item) => list[item] = (list[item] || 0) + 1, {})
.value();
console.log(itemCount['hammers']); //Expected: 2; Actual: undefined
console.log(itemCount); //Expected: object containing all names and values; Actual: 1
Not sure yet what I'm doing wrong, but I'm guessing it has to do with how I'm trying to use _.reduce(). However, at this point I'm kind of lost, so I'm not sure what to try next.
I'm certain this is the structure I want (I'm not looking for work-arounds), I'm just curious what I'm doing to make reduce apparently break, and how I can change it to work correctly so it'll give me back something that looks like
{'hammers': 2,
'wrenches': 3,
'screw drivers': 2}
etc.
.reduce's callback should return the initialValue i.e. the empty object, if you don't use the arrow function what you did is like
.reduce(function (list, item) {
return list[item] = (list[item] || 0) + 1
}, {})
It should be
.reduce(function (list, item) {
list[item] = (list[item] || 0) + 1
return list
}, {})
And if you want a one liner you can use
.reduce((list, item) => (list[item] = (list[item] || 0) + 1, list), {})
Example
console.log(['a', 'a', 'b', 'c'].reduce((list, item) => (list[item] = (list[item] || 0) + 1, list), {}))

Categories