Map keys into array according to values - javascript

what's the most efficient way to map keys into array according to values based on the condition of the value?
For example, I have a map that contains the File object as the key and boolean as the value like this:
map = new Map([
[file, true],
[file1, true],
[file2, false],
[file3, true],
]);
Can I ask what's the shortcut way of creating an array of file objects if map value === true?
Intended outcome
files = [file,file1,file3];
Appreciate your help thanks!

You can use entries to get the keys and the values of the map, then filter it by whether a value (the condition) is true, and then .map to turn the [key, value] into just the key:
const map = new Map([
['file', true],
['file1', true],
['file2', false],
['file3', true],
]);
const files = [...map.entries()]
.filter(([_, cond]) => cond)
.map(([key]) => key);
console.log(files);

A simple forEach loop could do the trick here.
const map = new Map([
['test', true],
['test2', true],
['test3', false],
['test4', true],
]);
const files = [];
map.forEach((value, key, map) => {
if (value) {
files.push(key)
}
});
console.log(files);

You could use Map.entries with filter and map to achieve this. The basic idea is
Get an array of all keys/values with Map.entries
filter that array to only the entries with the value true
use map to convert from Map entries to array elements.
the code would look something like this.
map.entries().filter(entry=>entry[1]).map(entry=>entry[0]);

The answers above work but if you're after the fastest, perhaps surprisingly using a for loop is faster than the prototype Map and array methods
aka:
myMap = new Map([
["file", true],
["file1", true],
["file2", false],
["file3", true],
]);
const fastest = (files) => {
const map = [...files]
const out = []
for (let i=0; i<map.length; i++){
if (map[i][1]){
out.push(map[i][0])
}
}
return out
}
console.log(fastest(myMap))
https://coderwall.com/p/kvzbpa/don-t-use-array-foreach-use-for-instead
There are many articles and a lot of literature about this if you have a look around

Related

Convery JS Object to array - keep key & value

I am trying to convert an object (updatedConfig) to an array (configArray), while maintaining the same structure (and avoid further nesting).
I have tried declaring a new array const and using Object.entries to push the keys & values.
I am able to get the keys but am having trouble figuring out how to achieve the nesting of array.
const configArray = [];
Object.entries(updatedConfig).forEach(([key, value]) => {
configArray.push(key);
})
Here is the object in question:
You can try something like this using Object.entries and Array.map
const configObject = {
key1: 'value',
key2: 1,
key3: [1, 2, 3]
}
const configArray = Object.entries(configObject).map(([key, value]) => ({key, value}))
console.log(configArray)

Filter object based on condition

I have an object as
sports={
"cricket":true,
"football":true,
"tennis":false
}
I want to filter all the sports which are true into an array like [cricket,football]
follow above code returns keys of true value in array like [cricket,football]
const sports = {
cricket: true,
football: true,
tennis: false,
};
const result = Object.keys(sports).filter((current) => {
return sports[current];
});
Use a for...in structure:
sports={
cricket:true,
football:true,
tennis:false
}
const result = []
for(const sport in sports) {
if (sports[sport]) result.push(sport)
}
console.log(result)
more info about for...in: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
var sports_arr = Object.keys(sports);
var tmp = [];
for(var i = 0; i < sports_arr.length && sports[sports_arr[i]]; i++)
tmp.push(sports_arr[i]);
You could use Object.entries(), Array.prototype.filter() and Array.prototype.map() like so:
const sports = {
cricket:true,
football:true,
tennis:false,
};
console.log(Object.entries(sports).filter(([key, value]) => value).map(([key, value]) => key));
Object.entries() returns an array with key-value pairs:
[
['cricket', true],
['football', true],
['tennis', false],
]
You can then check the second element on each entry to filer out the ones that are false:
[
['cricket', true],
['football', true],
]
And then use map to keep only the first element:
[
'cricket',
'football',
]
As posted by #David784 in the comments, this is the simplest solution. No need to complicate it any further:
const sports = {
cricket:true,
football:true,
tennis:false,
};
const result = Object.keys(sports).filter(key => sports[key]);
console.log(result);
Merely get an array of the keys (Object.keys(sports)) and then discard the ones for which the value isn't true with a .filter().

Create 1d array from 2d array's sub objects using [filter, map, some, reduce etc]

I have an object as below:
Response{
result:[{products:[o1,o2,o3]},{products:[o5,o7,o8]},{products:[o11,o12,o13]}]
}
how can I create an array of all the product objects o1, o2 ... using functional programming (filter, map, some, reduce etc)?
the output should be:
outArray = [o1,o2,o3,o5,o7,o8,o11,o12,o13]
You can use combine concat with map for this purpose:
const products = [{products:[1,2,3]},{products:[5,7,8]},{products:[11,12,13]}];
const result = Array.prototype.concat.apply([], products.map(item => item.products));
console.log(result);
Using Array#reduce, Array#push, destructuring and spread syntax:
const data = {result:[{products:['a','b','c']},{products:['a','b','c']},{products:['a','b','c']}]}
const res = data.result.reduce((a, {products}) => {
a.push(...products);
return a;
}, [])
console.log(res);
A little less verbose alternative that still uses map and the spread operator.
const init = [
{products: [1, 2, 3]},
{products: [5, 7, 8]},
{products: [11, 12, 13]}
];
const result = [].concat(...init.map(x => x.products));
console.log(result);
You can use map and join together to get desire output
let result =[{products:['o1','o2','o3']},{products:['o5','o7','o8']},{products:['o11','o12','o13']}];
let data = [result.map(function(o){ return o.products})].join(',').split(',');
console.log(data);
Use Array.prototype.flatMap.
const data = [{products: ['o1','o2','o3']}, {products: ['o5','o7','o8']}, {products: ['o11','o12','o13']}];
console.log(data.flatMap(p => p.products));

Get array of keys based on values from another array

Say I have an array of objects that looks like this
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
How would I iterate though this to return a new array of true values that looks like this:
let newArray = ['item1', 'item3']
I found this function but it only returns single items:
function findKey(map, term) {
var found = [];
for(var property in map) {
if(map.hasOwnProperty(property)) {
for(var key in map[property]) {
if(map[property].hasOwnProperty(key) && key === term) {
found.push(property);
}
}
}
}
return found;
}
Assuming myArray always contains objects with only 1 property.
let newArray = myArray
.map(item => Object.entries(item)[0])
.filter(([key, value]) => value)
.map(([key, value]) => key)
You could access the first key of each array item via Object.keys(), and use this to filter items with a true value for that first key, and then complete the process with a call to map() to transform the item to a value based on the same "first key" technique:
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
let result = myArray
.filter(item => item[ Object.keys(item)[0] ] === true)
.map(item => Object.keys(item)[0])
console.log(result)
Use the function reduce to build the desired output. The handler of the function reduce will get the keys and check for each value === true.
This approach checks for the whole set of keys within an object. Further, this way you only use one loop.
let myArray = [{item1: true},{item2: false},{item3: true},{item4: false}],
result = myArray.reduce((a, c) => a.concat(Object.keys(c).filter(k => c[k] === true)), []);
console.log(result);
Something much optimized than the accepted answer would look like this:
const arr = [
{ item1: true },
{ item2: false },
{ item3: true },
{ item4: false }
]
const result = [];
const len = arr.length;
for (let i = 0; i < len; ++i) {
const obj = arr[i];
const key = Object.keys(obj)[0];
if(obj[key]) {
result.push(key);
}
}
console.log(result);
There is only one loop over the array, instead of map and filter which ends up looping twice.
Shortest
let newArray = myArray.map( x=>Object.keys(x)[0] ).filter( (k,i)=>myArray[i][k] );
In above solution first we use: map which works as for-loop to get array of keys (using Object.keys) ["item1", "item2", "item3", "item4"]. Then we filter that array by choose only those keys for which original array object has true. e.g myArray[0]["item1"] -> true (we use fact that filter funtion takes array element (k) and its index (i) which is the same for elements in myArray). In map and filter we use arrow functions.

How can I Display a JavaScript ES6 Map Object to Console?

I'm using repl.it/languages/javascript.
Do I have to convert it to an object before I print it out?
I've tried
const mapObject = new Map();
mapObject.set(1, 'hello');
console.log(JSON.stringify(mapObject));
console.log(mapObject);
The results are always empty object.
When I use
console.log([...mapObject]);
It prints out an array format.
There is a more simpler solution you can try.
const mapObject = new Map();
mapObject.set(1, 'hello');
console.log([...mapObject.entries()]);
// [[1, "hello"]]
console.log([...mapObject.keys()]);
// [1]
console.log([...mapObject.values()]);
// ["hello"]
Note: This answer is only relevant to the repl.it sandbox environment OP is using
Since you said in the comments that you're using repl.it, there's a trick you can use to write your own "logging strategy".
Note that you shouldn't use this trick in production, mainly because it edits a native prototype. In some Node environment, in your own code, it could be useful though.
The idea is to create an inspect method for Map that iterates over the entries:
Map.prototype.inspect = function() {
return `Map(${mapEntriesToString(this.entries())})`
}
function mapEntriesToString(entries) {
return Array
.from(entries, ([k, v]) => `\n ${k}: ${v}`)
.join("") + "\n";
}
You can see that repl.it supports it here
console.log(new Map([["a", 1], ["b", 2]]));
// Logs:
/*
Map(
a: 1
b: 2
)
*/
I realize this is most likely intended for the browser console but this also occurs in Node. So, you may use this in Node to view Maps (or an Object that may contain Maps):
import * as util from "util";
const map: Map<string, string> = new Map();
map.set("test", "test");
const inspected: string = util.inspect(map);
console.log(inspected);
For simple maps that are of depth 1, just use Object.fromEntries([...map]) to convert your object entries array back to a console loggable object:
const simpleObj = {
a: [1, 2, 3],
b: {c: {d: 42}}
};
const map = new Map(Object.entries(simpleObj));
console.log(Object.fromEntries([...map]));
This fails for complex nested maps, however. For that, we can recursively convert any Maps to objects and then log it as normal. Here's a proof-of-concept on a complex structure combining plain objects, Maps, arrays and primitives. Don't expect it to cover every edge case out of the box, but feel free to point out improvements.
const convertMapToObjDeeply = o => {
const recurseOnEntries = a => Object.fromEntries(
a.map(([k, v]) => [k, convertMapToObjDeeply(v)])
);
if (o instanceof Map) {
return recurseOnEntries([...o]);
}
else if (Array.isArray(o)) {
return o.map(convertMapToObjDeeply);
}
else if (typeof o === "object" && o !== null) {
return recurseOnEntries(Object.entries(o));
}
return o;
};
const mkMap = o => new Map(Object.entries(o));
const map = mkMap({
a: 42,
b: [1, 2, 3, mkMap({d: mkMap({ff: 55})})],
c: mkMap({
e: [4, 5, 6, {f: 5, x: y => y}, mkMap({g: z => 1})]
}),
h: {i: mkMap({j: 46, jj: new Map([[[1, 6], 2]])})},
k: mkMap({l: mkMap({m: [2, 5, x => x, 99]})})
});
console.log(convertMapToObjDeeply(map));
you can use console.log(mapObject.values())
Try this:
let mapObject = new Map();
mapObject.set("one", "file1");
mapObject.set("two", "file2");
mapObject.set("three", "file3");
console.log([...mapObject.entries()]);
the output will be:
[ [ 'one', 'file1' ], [ 'two', 'file2' ], [ 'three', 'file3' ] ]
The problem with this solution, is that the output changes if we add a previous string:
console.log("This is a map: " + [...mapObject.entries()]);
the output will be:
This is a map: one,file1,two,file2,three,file3
the solution can be found here

Categories