compare an array and object to see if item exists - javascript

I have the following:
An array
const myArray = ['john', 'frank', 'paul'];
then I have an array of objects
const myObjectArray = [
{name: 'nery', age: 34, present: true},
{name: 'john', age: 15, present: false},
etc
]
How can I check if myArray value is found in the myObjectArray?
I thought about looping through myArray and then in each iteration looping through myObjectArray to see if it is present. However this seems so 2001.
Any ideas?

You can use the Array.prototype.some and Array.prototype.includes functions.
const names = ['john', 'frank', 'paul'];
const people = [
{name: 'nery', age: 34, present: true},
{name: 'john', age: 15, present: false},
];
const exists = people.some(({ name }) => names.includes(name));
console.log(exists);

Array.prototype.find can find the first element in the provided array that satisfies the provided testing function.
const myArray = ["john", "frank", "paul"];
const myObjectArray = [
{ name: "nery", age: 34, present: true },
{ name: "john", age: 15, present: false },
];
res = myObjectArray.find((o) => myArray.includes(o.name));
console.log(res);

if you want to check if an item from first array is in the name of second array use some to return a boolean
const myArray = ["john", "frank", "paul"];
const myObjectArray = [
{ name: "nery", age: 34, present: true },
{ name: "john", age: 15, present: false },
];
res = myObjectArray.some((o) => myArray.includes(o.name));
console.log(res);
If you want to return the object that has same name from first array use filter
const myArray = ["john", "frank", "paul"];
const myObjectArray = [
{ name: "nery", age: 34, present: true },
{ name: "john", age: 15, present: false },
];
res = myObjectArray.filter((o) => myArray.includes(o.name));
console.log(res);

Related

Return array values which are not duplicates

var arr = [
{name:"Grace", age: "28"},
{name:"Peter", age: "15"},
{name:"Grace", age: "28"},
{name:"John", age: "16"},
{name:"Prince", age: "19"},
{name:"John", age: "16"}
];
I now want return only those which are unique as below
var new = [
{name:"Peter", age: "15"},
{name:"Prince", age: "19"},
];
You can use Map and reduce
First create a mapper based on name and count repetition of each name
Select only the values where repetition is exactly 1
const arr = [{name:"Grace", age: "28"},{name:"Peter", age: "15"},{name:"Grace", age: "28"},{name:"John", age: "16"},{name:"Prince", age: "19"},{name:"John", age: "16"}];
let mapper = arr.reduce( (op,inp) => {
let {name:key} = inp
op.set(key, op.get(key) || {value: inp, count:0})
op.get(key).count++
return op
},new Map())
let final = [...mapper.values()].reduce((op,{value,count}) => {
if(count === 1){
op.push(value)
}
return op
},[])
console.log(final)

How can I convert an array of objects into an array of objects with the same values but with modified keys?

I have an array with objects and want to convert this to an array containing the same values but with different key names. (JavaScript)
For example, an array of
[{name: "Bob", age: 50, person: true}, {name: "Jerry", age: 20, person: true}]
becomes
[{identification: "Bob", years: 50, person: true}, {identification: "Jerry", years: 20, person: true}]
Using the Map function works perfectly here.
const people = [
{name: "Bob", age: 50, person: true},
{name: "Jerry", age: 20, person: true}
];
const formatted = people.map((person) => ({
identification: person.name,
years: person.age,
person: person.person
});
This should work for this problem.
I think that you may use the map method this method returns and array with the same length as the one you are mapping:
const array = [{name: "Bob", age: 50, person: true}, {name: "Jerry", age: 20, person: true}];
let newKeysArray = array.map( a => {
let obj = {
identification: person.name,
years: person.age,
person: person.person
};
return obj
} );
So inside the map you are assigning the values that you need to a new object and return the object as the mapped item.
Just in case you prefer to modify the objects in place, you can make use of a strategy by nverba here:
let rows = [
{name: "Bob", age: 50, person: true},
{name: "Jerry", age: 20, person: true}
];
let keyMaps = [
['name', 'identification'],
['age', 'years'],
];
for(let keyMap of keyMaps)
for(let row of rows)
delete Object.assign(row, {[keyMap[1]]: row[keyMap[0]] })[keyMap[0]];
console.log(rows);
keyMap[1] is the new key. keyMap[0] is the old key. Object.assign takes the value of the old key and places it in the new key. The delete keyword is confusing, but it doesn't apply to row as a whole. It's only deleting the old key.

How to edit object array?

I want to edit JavaScript object.
I have an JavaScript object like this
data_without_id = [
0: {id: 1, name: "Mary", age: null}
1: {id: 2, name: "Bob", age: 33}
2: {id: 1, name: "Kelly", age: 40}
]
I want to convert this object into this
data_without_id = [
0: {id: 1, name: "Kelly", age: 40}
1: {id: 2, name: "Bob", age: 33}
]
What I need to do is:
Group by id
Get latest value.
I tried using Array.prototype.reduce(), but I can't get the result I need...
Using the function reduce would be as follow:
The function reduce for grouping and the function Object.values for extracting the values.
let data_without_id = [ { id: 1, name: "Mary", age: null }, { id: 2, name: "Bob", age: 33 }, { id: 1, name: "Kelly", age: 40 }],
result = Object.values(data_without_id.reduce((a, {id, name, age}) => {
a[id] = {id, name, age};
return a;
}, Object.create(null)));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use .reduce by making the accumulator an object that has keys of the id. This way you can overwrite any previously seen objects which had the same id, and then use Object.values to get your array of objects:
const data_without_id = [{id: 1, name: "Mary", age: null}, {id: 2, name: "Bob", age: 33}, {id: 1, name: "Kelly", age: 40}],
res = Object.values(data_without_id.reduce((acc, obj) =>
(acc[obj.id] = obj, acc)
, {}));
console.log(res);
You could just simply use a for/of loop to create a copy of the data where the last object with a particular id will always be the object returned in the output data. This avoids the "grouping" part of the code but still returns the correct data.
const data_without_id = [
{ id: 1, name: "Mary", age: null },
{ id: 2, name: "Bob", age: 33 },
{ id: 1, name: "Kelly", age: 40 }
];
function lastId(arr) {
const out = [];
for (let obj of arr) {
// If you don't create a copy of each object the returned
// data will simply be contain _references_ to the original
// data. Changes in the original data will be reflected
// in the returned data
out[obj.id - 1] = { ...obj };
}
return out;
}
const lastIds = lastId(data_without_id);
console.log(lastIds);

Ramdajs: How to filter a list based on a object property?

const abby = {name: 'Abby', attributes: {age: 7, hair: 'blond'}};
const fred = {name: 'Fred', attributes: {age: 12, hair: 'brown'}};
const rusty = {name: 'Rusty', attributes: {age: 10, hair: 'brown'}};
const alois = {name: 'Alois', attributes: {age: 15, disposition: 'surly'}};
const kids = [abby, fred, rusty, alois];
console.log = function(text) {
$('#console').append($('<div>').text(text));
};
// current code
console.log(R.filter(R.compose(R.propEq('hair', 'blond'), R.props('attributes')))(kids));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<div id="console"></div>
I want to get the objects whose hair is 'blond'. I tried using compose but unluckily it doesn't work. I am still new with ramda.
Your initial attempt is almost correct; R.props('attributes') should have been R.prop('attributes') instead:
R.filter(R.compose(R.propEq('hair', 'blond'), R.prop('attributes')))(kids)
However you may find it easier to use pathSatisfies if you need to assert against a nested property:
Returns true if the specified object property at given path satisfies the given predicate; false otherwise.
const {filter, pathSatisfies, equals} = R;
const abby = {name: 'Abby', attributes: {age: 7, hair: 'blond'}};
const fred = {name: 'Fred', attributes: {age: 12, hair: 'brown'}};
const rusty = {name: 'Rusty', attributes: {age: 10, hair: 'brown'}};
const alois = {name: 'Alois', attributes: {age: 15, disposition: 'surly'}};
const kids = [abby, fred, rusty, alois];
console.log(
filter(pathSatisfies(equals('blond'), ['attributes', 'hair']), kids)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
References
props
prop
pathSatisfies
it is year 2020, I guess use pathEQ is much simple
const R = require("ramda");
let out = "";
const abby = { name: "Abby", attributes: { age: 7, hair: "blond" } };
const fred = { name: "Fred", attributes: { age: 12, hair: "brown" } };
const rusty = { name: "Rusty", attributes: { age: 10, hair: "brown" } };
const alois = { name: "Alois", attributes: { age: 15, disposition: "surly" } };
const kids = [abby, fred, rusty, alois];
out = R.filter(R.pathEq(["attributes", "hair"], "blond"))(kids);

Iterating and filtering with ES6/lodash

We have an array of objects like:
const persons = [{
name: "john",
age: 23
}, {
name: "lisa",
age: 43
}, {
name: "jim",
age: 101
}, {
name: "bob",
age: 67
}];
And an array of a attribute values of the objects in object
const names = ["lisa", "bob"]
How can we find persons with name in the names array using es6, like:
const filteredPersons = [{
name: "lisa",
age: 43
}, {
name: "bob",
age: 67
}];
ES6
Use filter function with predicate and in it check the existence of the name in the names array.
const persons = [
{name: "john", age:23},
{name: "lisa", age:43},
{name: "jim", age:101},
{name: "bob", age:67}
];
const names = ["lisa", "bob"];
const filtered = persons.filter(person => names.includes(person.name));
console.log(filtered);
You can use filter() and inlcudes() to get required result.
DEMO
const persons = [{
name: "john",
age: 23
}, {
name: "lisa",
age: 43
}, {
name: "jim",
age: 101
}, {
name: "bob",
age: 67
}];
const names = ["lisa", "bob"];
console.log(persons.filter(({
name
}) => names.includes(name)))
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would suggest to use indexOf as includes does not work in IE browser. Also, using {name} works as Destructuring assignment that will hold the value of name property of the object.
const persons = [{
name: "john",
age: 23
}, {
name: "lisa",
age: 43
}, {
name: "jim",
age: 101
}, {
name: "bob",
age: 67
}];
const names = ["lisa", "bob"];
console.log(persons.filter(({name}) => names.indexOf(name) !== -1))
lodash
You can try following
const persons = [{name: "john", age: 23},
{name: "lisa",age: 43},
{name: "jim", age: 101},
{name: "bob",age: 67}];
const names = ["lisa", "bob"]
const filteredPersons = _.filter(persons, function(person) {
return _.indexOf(names, person.name) !== -1;
});
console.log(filteredPersons);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
In case you want to perform it in n complexity, here is a way to do it:
Create a map with key as person's name and value as person's object.
Map the criteria array and extract the person objects from the map create in step 1.
Here is a working demo:
const persons = [{
name: "john",
age: 23
}, {
name: "lisa",
age: 43
}, {
name: "jim",
age: 101
}, {
name: "bob",
age: 67
}];
const names = ["lisa", "bob"];
const map = persons.reduce((acc, item) => {
acc[item.name] = item;
return acc;
}, {});
const result = names.map(name => map[name]);
console.log(result);
Note: This solution assumes that only unique person names are in the source array. It needs to be tweaked to handle duplicates.
See Closures, Set, and Array.prototype.filter() for more info.
// Input.
const persons = [{name: "john",age: 23}, {name: "lisa",age: 43}, {name: "jim",age: 101}, {name: "bob",age: 67}]
const names = ["lisa", "bob"]
// Filter.
const filter = (A, B) => (s => A.filter(x => s.has(x.name)))(new Set(B))
// Output.
const output = filter(persons, names)
// Proof.
console.log(output)

Categories

Resources