Given the following object
var obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]}
is it possible, using Object.keys (no loop), to get key (low/medium/high) by one of the corresponding values?
Maybe something like this:
var obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]};
function getKey(n) {
return Object.keys(obj).find(k => obj[k].includes(n));
}
If you would really like to avoid for loop, you can use Array#reduce instead.
var obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]};
const fn = (value, arr) =>
Object.entries(arr)
.reduce((s, [key, a]) => (a.indexOf(value) > -1 ? key : s), null);
console.log(fn(7, obj));
console.log(fn(1, obj));
You can define a function to return the key according to the value passed.
the function uses Object.keys and Array.find()
var obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]};
const findKeyByValue = (value)=>{
return Object.keys(obj).find(key => obj[key].find(element => element === value))
}
console.log(findKeyByValue(8))
It's not possible to do this without a custom approach, there are a lot of ways for accomplishing what you want.
This approach uses the Proxy object to find the key by the accessed property and keeps the entries to be able to provide quick access.
const obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]},
decorate = (o) => {
const entries = Object.entries(o);
return new Proxy(o, {
get(_, accessedProperty) {
let [key] = (entries.find(([_, values]) => values.includes(+accessedProperty)) || []);
return key;
}
});
},
decoratedObj = decorate(obj);
console.log(decoratedObj[1]);
console.log(decoratedObj[4]);
console.log(decoratedObj[10]);
console.log(decoratedObj[11]);
You can do it with Object.keys, Object.values, Array#findIndex and Array#some.
var obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]};
function mySearch(obj,search) {
return Object.keys(obj)[(Object.values(obj).findIndex(el => el.some(val => val===search)))];
}
console.log(mySearch(obj, 5));
console.log(mySearch(obj, 8));
You're looking for a different data structure than a basic object. Have a look at the bidirectional map. This is a data strucure that allows you to look up values by their key, and keys by their value.
I can recommend this implementation. It's part of mnemonist, which has a bunch of handy data structures for different use cases!
import BiMap from 'mnemonist/bi-map';
const obj = {'low': [1, 2, 3], 'medium': [4, 5, 6], 'high': [7, 8, 9, 10]};
const lookupTable = BiMap.from(obj);
console.log(lookupTable.get('low'))
// > [1,2,3]
console.log(lookupTable.inverse.get([1,2,3]))
// > 'low'
Related
I am wondering how you would go about deleting arrays that contain the same elements in a 2 dimensional array.
For example:
let 2dArr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
This array would delete the second and fourth elements, returning the 2d array:
returnedArr = [ [1, 2, 3],
[2, 4, 5],
[4, 3, 1] ];
How exactly could this be done, preserving the 2d array? I could only think to loop through elements, comparing elements via a sort, and deleting them as you go along, but this would result in an indexing error if an element is deleted.
1) You can easily achieve the result using reduce and Set as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.reduce((acc, curr) => {
const key = [...curr].sort((a, b) => a - b).join();
if (!set.has(key)) {
set.add(key);
acc.push(curr);
}
return acc;
}, []);
console.log(result);
2) You can also use filter as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.filter((curr) => {
const key = [...curr].sort((a, b) => a - b).join();
return !set.has(key) ? (set.add(key), true) : false;
});
console.log(result);
const seen = []
const res = array.filter((item) => {
let key = item.sort().join()
if(!seen.includes(key)){
seen.push(key)
return item
}
})
console.log(res)
You can use hash map
let arr = [ [1, 2, 3], [3, 2, 1],[2, 4, 5],[4, 5, 2],[4, 3, 1] ];
let obj = {}
let final = []
for(let i=0; i<arr.length; i++){
// create a key
let sorted = [...arr[i]].sort((a,b)=> a- b).join`,`
// check if this is not present in our hash map
// add value to final out and update hash map accordingly
if(!obj[sorted]){
obj[sorted] = true
final.push(arr[i])
}
}
console.log(final)
Using Array.prototype.filter() and a Set as thisArg
let arr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
let res = arr.filter(function(e){
const sorted = [...e].sort((a,b) => a-b).join('|');
return this.has(sorted) ? false : this.add(sorted)
},new Set)
console.log(res)
I have an array of arrays, and I want to map over it and just return the values of arrays, but when I map over it and log the result, it's just an array and I don't know how to map over my array and use it in other places.
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
const arrMap = arr.map((it) => it.map((itm) => itm));
console.log(arrMap);
//what I expected 1,2,3,4,5,6 , ...
//what I got [Array(3), Array(3), Array(3)]
Actually, I need the values for using them in somewhere else, but I don't know what to do.
I also used function for this but when I return the values and log them It's undefined:
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
const arrMap = (arr) => {
arr.forEach((element) => {
console.log(element);
//In here, everything works fine
return element;
});
};
console.log(arrMap);
//what I got undefined
Use flatMap -
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
const arrMap = arr.flatMap(m => m);
console.log(arrMap);
Why it won't work : map() is supposed to run on each element of an array and return a transformed array of the same length. You have three elements in your input array and will always get three elements in your mapped array.
Your expectations can be met by tweaking your code with forEach() if you want. With forEach() there is nothing returned and you will have to start with a separate array variable. Below code uses ...
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
let arrMap = [];
arr.forEach((it) => arrMap.push(...it));
console.log(arrMap);
But flatMap() is already there:
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
let ans = arr.flatMap(x => x);
console.log(ans);
Use flat if you just want to flatten the array:
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
console.log(arr.flat());
Use flatMap if you want to do something with each element before the array gets flattened.
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
const arrMap = arr.flatMap((el) => {
el.forEach((n) => console.log(n));
return el;
});
console.log(arrMap);
forEach doesn't return anything it's like a for loop but for array only.
Since you have double array you should flat it by using flatMap
const arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
const arrMap = arr.flatMap((it) => it);
console.log(arrMap);
Am trying form data from object array to array of arrays in JavaScript but am unable to get the result
Input Data { "sept" : [1,2,3], "oct" : [5,6,7] "Nov" : [7,8,9]}
Expected Output [["sept",1,2,3],["oct",5,6,7],["Nov",7,8,9]]
I have tried a lot I can able to get the keys by Object.Key() but can able to form the data with the value as expected output above, please help me to resolve this Thanks in advance
You could get the entries and map key and values in an array.
const
data = { sept: [1, 2, 3], oct: [5, 6, 7], Nov: [7, 8, 9] },
result = Object.entries(data).map(([k, v]) => [k, ...v]);
console.log(result);
Just iterate over properties using for .. in loop, you will get the result.
const obj = {
"sept": [1, 2, 3],
"oct": [5, 6, 7],
"Nov": [7, 8, 9],
}
const result = [];
for (const prop in obj) {
result.push([prop, ...obj[prop]]);
}
console.log(result)
Use Object.entries() and then .map() with ... - rest/spread operator
const object = {
september: [1, 2, 3],
october: [5, 6, 7],
november: [7, 8, 9],
}
const result = Object.entries(object).map(([key, value])=>[key, ...value])
You could use Object.entries then spread the values along with the key
const data = { sept: [1, 2, 3], oct: [5, 6, 7], Nov: [7, 8, 9] }
const res = Object.entries(data).map(([key, value]) => [key, ...value])
console.log(res)
The Ramda.js library has a function that does exactly this called toPairs()
https://ramdajs.com/docs/#toPairs
i'm trying to write a function to find the smallest number on an array of an array.
already tryed this, but i don't really know how to do when there is arrays on an array.
const arr = [4, 8, 2, 7, 6, 42, 41, 77, 32, 9]
const min = Math.min(arr)
console.log(min)
By taking ES6, you could use the spread syntax ..., which takes an array as arguments.
const arr = [4, 8, 2, 7, 6, 42, 41, 77, 32, 9];
const min = Math.min(...arr);
console.log(min);
With ES5, you could take Function#apply, which take this and the parameters as array.
const arr = [4, 8, 2, 7, 6, 42, 41, 77, 32, 9];
const min = Math.min.apply(null, arr);
console.log(min);
For unflat arrays, take a flatten function, like
const
flat = array => array.reduce((r, a) => r.concat(Array.isArray(a) ? flat(a) : a), []),
array = [[1, 2], [3, 4]],
min = Math.min(...flat(array));
console.log(min);
You can use map to iterate over the nested arrays and then use Math.min(...array) on each to get the minimum. The output from map is an array of minimum values.
const arr = [[4, 8, 2], [7, 6, 42], [41, 77, 32, 9]];
const out = arr.map(a => Math.min(...a));
console.log(out);
Use spread ... and flat:
const a = [[0, 45, 2], [3, 6, 2], [1, 5, 9]];
console.log(Math.min(...a.flat()));
Or you might use reduce:
const arr = [[7, 45, 2], [3, 6, 2], [1, 5, 9]];
let r = arr.reduce((a, e) => Math.min(a, ...e), Infinity)
console.log(r);
I am trying to create a function that will get the items that cannot be seen on the 2nd or 3rd and upcoming arrays passed within the function.
Right now my function gets only the similar items. How can I make it get the difference (w/c are the items that doesn't exist to the 2nd and 3rd and proceeding arrays.
const callM = function(arrays) {
arrays = Array.prototype.slice.call(arguments);
let result = [];
for(let i = 1; i < arrays.length; i++){
for(let x = 0; x < arrays[i].length; x++){
if(arrays[0].includes(arrays[i][x])){
result.push(arrays[i][x]);
}
}
}
return result;
};
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10])); // -> must be [1, 3, 4]
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8])); // -> must be [3,4]
The logic right now is a bit off as it gets the opposite. How do i fix this?
Also is there a way to do this using Higher Order functions such as reduce or filter?
Thanks!
I'd think about this differently. As the difference between two sets: array 0 and array 1...n
To get array 0, just shift it off the top
const arr0 = arrays.shift()
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
This removes the first array from arrays
Next we combine the remaining arrays
const arrN = arrays.reduce(function(prev, curr) {
return prev.concat(curr)
})
Ref: http://www.jstips.co/en/javascript/flattening-multidimensional-arrays-in-javascript/
Unneeded, handled by includes as mentioned by #Phil
Next filter duplicates from arrN by comparing with itself
const unique = arrN.filter(function(elem, index, self) {
return index == self.indexOf(elem);
})
Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Next filter with includes to find the difference (or union)
const diff = arr0.filter(function(item) {
return !arrN.includes(item))
}
Full snippet:
function callM(arrays) {
const arr0 = arrays.shift()
const arrN = arrays.reduce(function(prev, curr) {
return prev.concat(curr)
})
//const unique = arrN.filter(function(elem, index, self) {
// return index == self.indexOf(elem)
//})
return arr0.filter(function(item) {
return !arrN.includes(item)
})
}
console.log(callM([[1, 2, 3, 4, 5], [5, 2, 10]]))
console.log(callM([[1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8]]))
of course ES6 would be easier. ;)
const callM = (first, ...rest) => {
const arrays = [].concat(...rest)
return first.filter(item => !arrays.includes(item))
}
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10]))
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8]))
A short solution for small and medium sized arrays:
// Return elements in array but not in filters:
function difference(array, ...filters) {
return array.filter(el => !filters.some(filter => filter.includes(el)));
}
// Example:
console.log(difference([1, 2, 3, 4, 5], [5, 2, 10])); // [1, 3, 4]
console.log(difference([1, 2, 3, 4, 5], [5, 1, 10], [7, 2, 8])); // [3, 4]
For large inputs, consider creating a Set from all filters and filtering in linear time using set.has(el).
In order to fix your implementation, you could label the outer for-loop and continue from there whenever a filter contains one of the array elements. Only when all filters pass without match, you push the array element into the result:
// Return elements in array but not in filters:
function difference(array, ...filters) {
const result = [];
loop: for (const el of array) {
for (const filter of filters) {
if (filter.includes(el)) continue loop;
}
result.push(el);
}
return result;
}
// Example:
console.log(difference([1, 2, 3, 4, 5], [5, 2, 10])); // [1, 3, 4]
console.log(difference([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8])); // [3,4]
If you're willing to use Underscore, you can do this in one line of code:
console.log(_.difference([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8]))
https://jsfiddle.net/o1zuaa6m/
You can use array#reduce to create object lookup of all the other array excluding the first array. Then use array#filter to get the values which are not present in the object lookup
var callM = (first, ...rest) => {
var combined = rest
.reduce((res,arr) => res.concat(arr))
.reduce((o, v) => {
o[v] = true;
return o;
},{});
return first
.filter(v => !combined[v]);
}
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10])); // -> must be [1, 3, 4]
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8])); // -> must be [3,4]
The "proper" way to exclude values is usually to use a lookup hash set with the values to exclude:
const callM = (a, ...b) => (b = new Set(b.concat.apply(...b)), a.filter(v => !b.has(v)))
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10])); // [1, 3, 4]
console.log(callM([1, 2, 3, 4, 5], [5, 2, 10], [7, 1, 8])); // [3, 4]