I have an array of objects like this:
var data = [
{id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
{id:2,first_name:'Blaan',last_name:'Adey',age:35,birth:'2001-04-16'}
];
var searchColumn = ['first_name','last_name','birth'];
These values(searchColumn) may change and not be constant.
For this reason they must be read from the array
I want to do this now :
function searchData(Val){
var newData = [];
if (Val){
for (let i=0 ; i < data.length ; i++){
searchColumn.forEach(value => {
if (data[i][value].includes(Val)){
newData.push(data[i]);
}
}
}
}
}
searchData('L');
please guide me.
This should do.
You don't have to loop through the array, you can use build-in functions like map, some and filter to achieve this.
var data = [
{id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
{id:1,first_name:'John',last_name:'Bal',age:20,birth:'1992-01-12'},
{id:2,first_name:'Blaan',last_name:'Adey',age:35,birth:'2001-04-16'}
];
var searchColumn = ['first_name','last_name','birth'];
var search = (searchParam) => {
// map here applies the function (value) => searchColumn.some(property => value[property] === searchParam) ? value : null
// over every value in the array & some loops through every value in the search column
// looking for an object where one of the properties specified in searchColumn has a value that matches our search parameter
return data.map(value => searchColumn.some(property => value[property] === searchParam) ? value : null)
.filter(result => !!result); // here we use filter to remove the null values mapped in the map function
}
search('John');
// result -> [{id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
// -> {id:1,first_name:'John',last_name:'Bal',age:20,birth:'1992-01-12'}]
UPDATE: As suggested, an better solution:
var search = (searchParam) => {
return data.filter(value => !!searchColumn.some(property => value[property] === searchParam));
}
... a configurable, thus more generic, approach based on Array.prototype.filter and Function.prototype.bind ...
function doesItemMatchBoundPropertyValueAndSearch(item) {
const { keyList, search } = this;
return keyList.some(key => item[key].includes(search));
}
const sampleDataList = [
{id: 1, first_name: 'John', last_name: 'Doe', age: 20, birth: '1992-01-12'},
{id: 2, first_name: 'Blaan', last_name: 'Adey', age: 35, birth: '2001-04-16'},
];
const searchColumn = ['first_name', 'last_name', 'birth'];
console.log(
"search: 'L' :",
sampleDataList.filter(
doesItemMatchBoundPropertyValueAndSearch.bind({
keyList: searchColumn,
search: 'L',
})
)
);
console.log(
"search: 'o' :",
sampleDataList.filter(
doesItemMatchBoundPropertyValueAndSearch.bind({
keyList: searchColumn,
search: 'o',
})
)
);
console.log(
"search: 'n' :",
sampleDataList.filter(
doesItemMatchBoundPropertyValueAndSearch.bind({
keyList: searchColumn,
search: 'n',
})
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Related
I have a list of objects:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}]
I use the below methods to get duplicated objects(by name) and assign a prop isDuplicated:
const duplicatedNames = arrayOfObjects
.map(e => e['name'])
.map((e, i, final) => final.indexOf(e) !== i && i++)
.filter(obj => arrayOfObjects[obj])
.map(e => !arrayOfObjects[e]['name']);
const result = arrayOfObjects.filter((obj, i) => {
return duplicatedNames.includes(obj.name) && Object.assign(obj, { isDuplicated: true });
});
I receive an array like:
[{name: 'Elza', isDuplicated: true}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
I would like to mark only the second occurrence of duplicate- so i would like the result to be:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
Can anyone know how to do it base on my code?
Here is a function that checks if a name exist more then once.
let data = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}, {name: "Jerry"}, {name: "Jerry"}];
function checkDup(arr){
let cache = [];
return arr.map(({name}, index) => {
if(!cache.find(el => el.name == name)){
cache.push({name, index});
return {name, index};
}
let { index: cacheIndex } = cache.find(el => el.name === name);
return {name,index: cacheIndex , isDuplicated: true};
})
}
console.log(checkDup(data));
You could create a Set of names. If the size of the set is same as after the name has been added, then it's duplicate record.
const input = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}],
names = new Set;
for (const o of input)
if (names.size === names.add(o.name).size)
o.isDuplicate = true
console.log(input)
You can try this:
let users = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}]
let flags = [], output = [];
users.forEach(user => {
if (flags[user.name]) {
output.forEach(item => {
if (item.name === user.name) {
item.isDuplicated = true
output.push(user);
}
})
} else {
flags[user.name] = true;
output.push(user);
}
})
Given your original array A, you could create a temporary array B and, for each a element of A, check:
if B contains a.name, then set a.isDuplicated to true;
else, push a.name in B.
let A = [{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}];
let B = [];
A.forEach(a => {
if (B.includes(a.name)) {
a.isDuplicated = true;
} else {
B.push(a.name);
}
});
console.log(A);
You can use reduce with a helper object:
const collection = [{ name: 'Elza'}, { name: 'Tom'}, { name: 'Elza' }]
const helper = {}
const result = collection.reduce((acc, { name }) => {
if (helper[name]) {
return [...acc, { name, isDuplicate: true }]
}
helper[name] = 'x';
return [...acc, { name }]
}, [])
console.log(result)
I am trying to get the value feature_1 of a key name from the array data and set feature_1 as the key of another array asset which has an array as value.
Example :
//input:
data: {
name: "feature_1",
value_a: 1,
value_b: 2
}
//Output:
asset: {
feature_1:[1,2]
}
You can try:
var asset = {};
if ('name' in data) {
var tmp = [];
for (k in data){
if (k != 'name') tmp.push(data[k]);
}
asset[data['name']] = tmp;
}
and in case your interpreter supports ES6 you can use, for example:
let {name, ...v} = data;
let asset = {[name]: Object.values(v)};
If supports same keys in a JSON object ( It seems not ) You can do it like this:
let data= {
name: "feature_1",
value_a: 1,
value_b: 2,
value_x: 500,
name: "feature_2",
value_a: 17,
value_b: 21,
value_x: 510
}
console.log(
Object.entries(data).reduce((a,[key,value],index)=>{
if (key==='name')
return {index, assets: {...a.assets, [value]:[]}};
return {
index : a.index,
assets : {
...a.assets,
[Object.entries(a.assets)[a.index][0]] : [...Object.entries(a.assets)[a.index][1],value]
}};
},{index:0,assets:{}}).assets
);
But we know the correct way is using separated array rows.
This can be accomplished the following way:
const obj = {
data: {
name: "feature_1",
value_a: 1,
value_b: 2
}
};
const output = {
assets: {
[obj.data.name]: Object.values(obj.data).filter(el => el !== obj.data.name)
}
}
console.log(output);
I am looping though an object to retrieve some properties but for some reason I cannot access the value of a nested object property.
This is my looping function:
parseContacts = (contacts) => {
return contacts.map(contact => {
let parsedContact = {};
Object.keys(contact).forEach(key => {
if (key === 'givenName') {
parsedContact.firstName = contact[key];
} if (key === 'familyName') {
parsedContact.surname = contact[key];
} if (key === 'phoneNumbers') {
parsedContact.phoneNumber = contact[key][0].number;
}
})
return parsedContact;
})
}
firstName and surname work fine, but in the last if statement I get undefined. the property with key phoneNumbers it is an array of objects, and this is item 0 in the array:
{id: "302", label: "mobile", number: "+44 7X7X 50XX72"}
When I use this code instead:
} if (key === 'phoneNumbers') {
parsedContact.phoneNumber = contact[key][0];
}
without .number on the end I get the whole object back fine, I just can't get back only the number property from the object.
Update
On closer inspection, the array which has over 800 large objects in, some of the lengths of the phoneNumbers arrays were 0 so the property did not exist. This was causing the whole function to fail. Thanks for the comments below.
My solution was to add to the if statement:
if (key === 'phoneNumbers' && contact[key].length)
You can prevent the empty phoneNumbers array issue like this:
contact[key] && contact[key].length ? contact[key][0].number : ''
const parseContacts = contacts => {
return contacts.map(contact => {
let parsedContact = {}
Object.keys(contact).forEach(key => {
switch (key) {
case 'givenName':
parsedContact.firstName = contact[key]
break
case 'familyName':
parsedContact.surname = contact[key]
break
case 'phoneNumbers':
parsedContact.phoneNumber = contact[key] && contact[key].length ? contact[key][0].number : ''
}
})
return parsedContact
})
}
const contacts = []
for (let i = 0; i < 10; i++) {
contacts.push({
givenName: faker.name.firstName(),
familyName: faker.name.lastName(),
phoneNumbers: [
{
id: faker.random.uuid(),
label: 'mobile',
number: faker.phone.phoneNumber()
}, {
id: faker.random.uuid(),
label: 'mobile',
number: faker.phone.phoneNumber()
}
]
})
}
contacts.push({
givenName: faker.name.firstName(),
familyName: faker.name.lastName(),
phoneNumbers: []
})
contacts.push({
givenName: faker.name.firstName(),
familyName: faker.name.lastName(),
phoneNumbers: null
})
console.log('RESULT ' + JSON.stringify(parseContacts(contacts)))
<script src="https://rawgit.com/Marak/faker.js/master/examples/browser/js/faker.js"></script>
I have a function that searches an object, to see if a value exist in it but I can't get the value from it when I try to log it.
searchValue(object,value){
let valueExists = Object.keys(object).find(key => object[key].valueID === value );
console.log(valueExists);
}
You could use Object(o).values like :
let valueExists = Object.values(object).find(val => val === value )
console.log(valueExists)
JS Example :
function searchValue(object, value) {
let valueExists = Object.values(object).find(val => val == value)
console.log(valueExists)
}
let user = {
id: 12,
name: "aaa",
email: "aaaa#domain.com",
}
searchValue(user, "aaa")
If you already have value (as searchValue parameter) you don't need to "get" value because you already have it (below I simplify your implementation)
function searchValue(object, value) {
return Object.values(object).includes(value);
}
let obj = {a: "xx", b: "yy"};
let val = "yy"
if(searchValue(obj,val)) {
console.log("the object value exist and is:", val);
}
If you interest to find keys which are associated with value try this
function searchKeys(object, value) {
return Object.keys(object).filter(k=>object[k]==value);
}
let obj = {a: "xx", b: "yy", c:"xx"};
let val = "xx"
console.log("Keys contains 'xx' value:", searchKeys(obj,val));
To achieve expected result, use below option of using Object entries and looping with forEach for value
function searchValue(object,value){
Object.entries(object).forEach(v => {
if(v.indexOf(value) !== -1) console.log("valueExists")
});
}
let test = {
id : 11,
name: 'abc',
location: 'usa'
}
searchValue(test, 11)
I need to filter some data based on multiple values. Language, title and slug
[
{
de: "4567uy55",
en: "654321",
lang: [
{
id: "654321",
language: "English",
title: "Title1"
},
{
id: "4567uy55",
language: "German",
title: "Title2"
}
],
slug: 'some-slug'
},
...
]
What I have now returns all objects which have one or part of the filters(in case title is This is a title, the word this should match), but I need to return objects which have all of them.
I used an object flattner just to get all properties and values in one object, but I can't get it to filter the way I need it.
multiFilter = (arr, filters) => {
console.log(filters)
console.log(arr)
let newArray = []
for (let c of arr) {
let flatCourse = flatten(c)
for (let k in flatCourse) {
const keyArr = k.split('/')
const filterKeys = Object.keys(filters)
Object.keys(filters).map((key) => {
if (keyArr.includes(key)) {
const flatVal = flatCourse[k].toString().toLowerCase()
const filterVal = filters[key].toString().toLowerCase()
console.log(flatVal)
console.log(filterVal)
if (flatVal.includes(filterVal)) {
arr = []
arr.push(c)
newArray.push(c)
}
}
})
}
}
return newArray
}
Filters look like this:
[
language:["English"],
title: ["Some title"],
slug:["some slug"]
]
Instead of mixing for loops and functional chaining you could just go with one of them:
multiFilter = (arr, filters) =>
arr.map(flatten).filter(el => // filter out elements from arr
Object.entries(filters).every(([fKey, fValues]) => // ensure that every key is included in the object
Object.entries(el).some(([oKey, oValue]) =>
oKey.split("/").includes(fKey) && fValues.includes(oValue)// make sure that at least one of the values equals the elements value
)
)
);
arr.filter(course => {
// Returns an array of booleans corresponding to whether or not each filter condition is satisfied
return Object.keys(filters).map(key => {
return filters[key].map(filter => {
// Special case here because lang is an array
if (key == 'language' && course.lang != undefined) {
return course.lang.some(lang => lang[key].includes(filter))
}
if (course[key] == undefined) {
return false
}
return course[key].includes(filter)
}).every(result => result == true)
}).every(result => result == true)
})