Filter Array from array - javascript

I want to filter the objects from array:
let x = [{a: 100, categories: [22, 23 ]
}, {a: 101, categories: [20, 21 ] }];
let y = [22]; //can be multiple
let result = x.filter(i => y.includes(i.categories) );
console.log(result);
// result = []
Expected Output:
[{a: 100, categories: [22, 23 ]}]
but I get empty array.

Use some to see if some of the items are in the categories array.
let x = [{a: 100, categories: [22, 23 ] }, {a: 101, categories: [20, 21 ] }];
let y = [22]; //can be multiple
let result = x.filter(i => y.some(a => i.categories.includes(a)));
console.log(result);

You're checking whether the entire array i.categories is in y, use Array.prototype.some to check if any element of i.categories is in y:
let x = [{a: 100, categories: [22, 23 ] }, {a: 101, categories: [20, 21 ] }];
let y = [22]; //can be multiple
let result = x.filter(i => y.some(x => i.categories.includes(x)));
console.log(result);

If x, .categories, or y is significantly large, you can achieve a significant speed improvement by first converting y to a Set. Set.prototype.has provides much faster lookup times, O(1), compared to Array.prototype.includes, O(n) -
const x =
[ { a: 100, categories: [ 22, 23 ] }
, { a: 101, categories: [ 20, 21 ] }
, { a: 102 }
]
const y =
[ 22 ] //can be multiple
const ySet =
new Set(y) // has O(1) lookup
let result =
x.filter(({ categories = [] }) =>
categories.some(c => ySet.has(c)) // <-- use set lookup
)
console.log(result)
// [ { a: 100, categories: [ 22, 23 ] } ]

Related

compare two array of objects keys, original array should mutate in javascript

How can we compare two array of objects on the basis of their keys or properties of object in javaScript?
for an example:
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
result1.filter(function (obj) {
return !result2.some(function (obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1?.forEach((x, index1) => {
key2?.forEach((y, index2) => {
console.log(index1, index2)
if (x === y) {
return obj[x] === obj2[y];
}
});
});
});
});
console.log(result1)
output: current output
expected output:
result1 =
[
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
I just try this solution in a different way, We can also achieve this requirement by doing deep copy of original array and then mutate it using forEach().
Live Demo :
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 }
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 }
];
const clone = structuredClone(result1);
clone.forEach((obj, index) => {
result1[index] = {};
Object.keys(result2[index]).forEach(key => {
result1[index][key] = obj[key]
});
});
console.log(result1);
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
let temp = []
result1.map(function(obj) {
return !result2.some(function(obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1.forEach((x) => {
key2.forEach((y) => {
if (x === y) {
obj[x] === obj2[y] ? temp.push({
[x]: obj[x]
}) : null;
}
})
});
})
})
console.log(temp);
try this code
You are getting the result1 array back beacause the array is not getting filtered.
The filter function is not getting anything from returned as the first foreach loop is not returning and the some function is also not returning anything
Now you can use map function instead of filter as the function is not returning anything
const filterKeysBasedOnFirstArrayOfObjects = <
T extends Record<string, unknown>
>(
arr1: T[],
arr2: T[]
) => {
const keys = _.intersection(
...arr1.map((obj) => Object.keys(obj)),
...arr2.map((obj) => Object.keys(obj))
);
return arr1.map((obj) => _.pick(obj, keys));
};
A more concise approach using lodash.

Merge a second object array with my array by index regardless of lengths

I have two array of objects with no common properties:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
I want to merge the props of b into a. Initially, I tried
let m = a.map((i,x) => ({id: i.id, day: b[x].day}));
This worked just fine as long as the lengths of both the arrays were the same. But when b was shorter or a was shorter, that would result in an error
Uncaught TypeError: Cannot read properties of undefined (reading 'day')
I don't really care about the length of b, all I want is a, and if b has an element at the same index, I want that b.day.
I ended up doing this:
let a = [
{id: 1},
{id: 2},
{id: 3},
];
let b = [
{day: 12},
{day: 15}
];
let m = [];
a.forEach((i, x) => {
let item = { id: i.id };
if (b.length > x) {
item['day'] = b[x].day;
}
m.push(item);
});
console.log(m);
This works fine, but it is decidedly uncool. I know this is probably more readable, but, go with me on this one.
Is there a way to make this more ES6 friendly? Is there a shorter / more concise way of achieving this please?
You could map the properties with spreading. If value at index is undefined, it acts like an empty object.
const
a = [{ id: 1 }, { id: 2 }, { id: 3 }],
b = [{ day: 12 }, { day: 15 }],
m = a.map((o, i) => ({ ...o, ...b[i] }));
console.log(m);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If I understood your question correctly.
A simple way of merging 2 arrays while also merging the objects at the same index:
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
let m = [];
//merge a and b together in m
m = a.map((item, index) => (b[index] ? { ...item, ...b[index] } : item));
console.log(m);
//output
m= [
{
"id": 1,
"day": 12
},
{
"id": 2,
"day": 15
},
{
"id": 3
}
]
Create a new array with the maximum length of both arrays. Loop through this array and return the objects from both a and b array.
let a = [{ id: 1 }, { id: 2 }, { id: 3 }];
let b = [{ day: 12 }, { day: 15 }];
const dummyArray = new Array(Math.max(a.length, b.length)).fill(0)
let m = dummyArray.map((_, index) => ({...a[index], ...b[index]}));
console.log(m);

sort and rearrange arrays basked on key value pair objects in javascript

I have 3 or more arrays that show prices (p) based on weight (w) breakpoints with unique identifiers for every array (i) such as the bellow.
var arr1 = [{w:1,p:10,i:"car1"},{w:2,p:15,i:"car1"},{w:3,p:21,i:"car1"}]
var arr2 = [{w:1,p:12,i:"car2"},{w:2,p:13,i:"car2"},{w:3,p:22,i:"car2"}]
var arr3 = [{w:1,p:9,i:"car3"},{w:2,p:12,i:"car3"},{w:3,p:33,i:"car3"}]
I want to generate "pricelist" arrays based cheapest, second cheapest, third cheapest etc.. such
var cheap1 = [{w:1,p:9,i:"car3"},{w:2,p:12,i:"car3"},{w:3,p:21,i:"car1"}]
var cheap2 = [{w:1,p:10,i:"car1"},{w:2,p:13,i:"car2"},{w:3,p:22,i:"car2"}]
var cheap3 = [{w:1,p:12,i:"car2"},{w:2,p:15,i:"car1"},{w:3,p:33,i:"car3"}]
what could be the fastest way to produce such an output.
I tried merging them into one array then sorting them out then looping over the array and pushing the objects into the new arrays based on if the indexes of the objects that had (w) value was equal to the previous (w) value, but it just wouldn't work and i cant seem find a way to solve this.
i tried multiple if then statements in multiple for loops and that worked out but the issue is that i might have some 20 arrays that i want to compare and if statements wont be viable.
appreciate the help!
You could sort by w property first and then by p. For getting a result of the sorted array pushthe object to the array by the remainder of the index.
const
array1 = [{ w: 1, p: 10, i: "car1" }, { w: 2, p: 15, i: "car1" }, { w: 3, p: 21, i: "car1" }],
array2 = [{ w: 1, p: 12, i: "car2" }, { w: 2, p: 13, i: "car2" }, { w: 3, p: 22, i: "car2" }],
array3 = [{ w: 1, p: 9,i: "car3" }, { w: 2, p: 12,i: "car3" }, { w: 3, p: 33, i: "car3" }],
[cheap1, cheap2, cheap3] = [...array1, ...array2, ...array3]
.sort((a, b) => a.w - b.w || a.p - b.p)
.reduce((r, o, i) => {
(r[i % 3] ??= []).push(o);
return r;
}, []);
console.log(cheap1);
console.log(cheap2);
console.log(cheap3);
.as-console-wrapper { max-height: 100% !important; top: 0; }

array + matrix = array of objects

I have two arrays:
arr1 = [name, speed, power, energy];
arr2 = [
[Ed, 10, 20, 30],
[Robert, 15, 25, 35],
[Paul, 8, 18, 28]
];
How can I combine the two array's to an array of objects, using the first array for keys and the second one for values?
arr3 = [
{
name: "Ed",
speed:"10",
power:"20",
energy:"30"
},
{
name: "Robert",
speed:"15",
power:"25",
energy:"35"
},
{
name: "Paul,
speed:"8",
power:"18",
energy:"28"
}
];
You can simply create an array of objects using map
arr2.map(row => {
const name = item[0];
const speed = item[1];
const power = item[2];
const energy = item[3];
return { name, speed, power, energy }
})
Running this on your given arr2 gives the following result
var arr2 = [['Ed', 10, 20, 30],['Robert', 15, 25, 35],['Paul', 8, 18, 28]];
var arr3 = arr2.map(row => {
const name = item[0];
const speed = item[1];
const power = item[2];
const energy = item[3];
return { name, speed, power, energy }
});
console.log(arr3)
// arr3 = [
// {name: "Ed", speed:10, power:20, energy:30},
// {name: "Robert", speed:15, power:25, energy:35},
// {name: "Paul", speed:8, power:18, energy:28}
// ]
Firstly, I am assuming the tokens name, speed, power, energy are actually strings and you forgot to include the quotes.
The Object.fromEntries method takes an array of tuples (two-item arrays) and converts it into an object.
If we zip the keys from arr1 with the values from each array in arr2, we can acheive the desired mapping.
arr1 = ["name", "speed", "power", "energy"];
arr2 = [["Ed", 10, 20, 30],["Robert", 15, 25, 35],["Paul", 8, 18, 28]];
arr3 = arr2.map(objArr =>
Object.fromEntries(arr1.map((key, i) =>
[key, objArr[i]] // key-value tuple
))
)
console.log(arr3);
Ruby has this really useful method called zip, so you want basically that for each of arr2 but in JavaScript. In other words, zip arr1 keys with each person's properties.
Below is a snippet that implements a basic zip function and then uses it to create the object in the format you're looking for:
arr1 = ["name", "speed", "power", "energy"];
arr2 = [
["Ed", 10, 20, 30],
["Robert", 15, 25, 35],
["Paul", 8, 18, 28],
];
Array.prototype.zip = function(a) {
return this.map((k, i) => [k, a[i]]);
};
arr3 = arr2.map(p => Object.fromEntries(arr1.zip(p)));
console.log(arr3);

Convert two arrays into an object

var foo = { "a": [1,2,3] }
var bar = { "b": [7,8,9] }
output should look like this
[ {a: 1, b: 7}, {a: 2, b: 8}, {a:3, b: 9}]
How can I do this using ramda or javascript functional programming ?
I have done this using for loop i = 0, is it possible using functional ramda programming
If both arrays are always the same length, you can do this using map.
function mergeArrays(arr1, arr2) {
return arr1.map(function(item, index) {
return {
a: arr1[index], //or simply, item
b: arr2[index]
};
});
}
var a = [1, 2, 3];
var b = [7, 8, 9];
var joined = mergeArrays(a, b);
document.getElementById('result').innerHTML = JSON.stringify(joined, null, 2);
<pre id="result">
</pre>
You can achieve this using R.transpose to convert an array of [[1,2,3], [7,8,9]] to [[1, 7], [2, 8], [3, 9]] and then map over it with R.zipObj.
const fn = R.compose(
R.map(R.zipObj(["a", "b"])),
R.transpose
)
const a = [1, 2, 3], b = [7, 8, 9]
const result = fn([a, b])
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
If you would prefer to pass a and b as two arguments to fn rather than an array then you can swap R.transpose in the example above with R.unapply(R.transpose).
Assuming you want [{a:1,b:7},{a:2,b:8},{a:3,b:9}] it can be done pretty easily with map using the index to get the value in b:
var result = a.map((v, i) =>({ a: v, b: b[i] }));
i am having an array
const peopleObject = { "123": { id: 123, name: "dave", age: 23 },
"456": { id: 456, name: "chris", age: 23 }, "789": { id: 789, name:
"bob", age: 23 }, "101": { id: 101, name: "tom", age: 23 }, "102":
{ id: 102, name: "tim", age: 23 } }
for this particular i have created a code that convrts array to object i hope this is usefull for you
const arrayToObject = (array) =>
array.reduce((obj, item) => {
obj[item.id] = item
return obj
}, {})
const peopleObject = arrayToObject(peopleArray)
console.log(peopleObject[idToSelect])
Your expected output doesn't have a valid format. You should store the data in array. Like ,
var output = [];
var a = [1,2,3], b = [7,8,9];
for(var i=0; i< a.length; i++){
var temp = {};
temp['a'] = a[i];
temp['b'] = b[i];
output.push(temp);
}
You cannot store the result in an object the way you want. Objects are key-value pairs. But what you expect is only the values without keys which is not possible!
create function form ramda's addIndex and map
const data = { keys: ['a', 'b', 'c'], values: ['11', '22', '33'] }
const mapIndexed = R.addIndex(R.map)
const result = mapIndexed((item, i) => {
return { [item]: data.values[i] }
}, data.keys)
You will get an array of objects

Categories