new Array Conditional values - javascript

I need to create a new array as you can see it has a key value that specifies the latitude and longitude.
I want the key values ​​that are equal to be set as 1 only but according to who has the highest count
[
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
]
let result = count.filter((e) => e && e.count && e.key == e.key);
let datas = result;

Is this what you're looking for?
const result = arr.reduce((acc, cur) => {
const matchIndex = acc.findIndex(saved =>
saved.latitud === cur.latitud
&& saved.longitud === cur.longitud
);
if (matchIndex !== -1) {
if (cur.count > acc[matchIndex].count) {
acc.splice(matchIndex, 1, cur);
}
return acc;
}
return [...acc, cur];
}, []);

It looks like the array contains objects that differ mostly by their count props but have several other duplicate props. I think I understand the OP to want to remove these almost-duplicates retaining the one with the highest count.
One way to do this is to sort the array to be descending by count, walk through them, pushing onto a result only those that aren't already in the result.
The only thing not super clear in the OP is what constitutes sameness besides the count field. Here, we guess that the coment_calification key being the same means the objects are to be treated as duplicate.
const objects = [
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
];
objects.sort((a,b) => b.count-a.count) // sort descending
const result = [];
for (let object of objects) {
// supposing matching coment_calification props means a match
let alreadyInResult = result.find(r => r.coment_calification === object.coment_calification)
if (!alreadyInResult) result.push(object);
}
console.log(result)

Related

I need to search data in an array according to filter and set start form index of 1

I need to search data in an array according to filter so I am able to do it I am searching data according to name and id but in the backend in index 0 I am not getting and name and id only getting one number so when I search data I am getting an undefined error so what my task is I need to set filter to start searching from index 1 mean ignore index 0
coming data example from a backend
[
2,
{
search_id: "10000107",
name: "dev name",
},
{
search_id: "10000106",
name: "alberto",
},
]
function handleSearch(term) {
const dummy = props.new_alert_list.filter((item) =>
item.name.toLowerCase().includes(term)
);
const dummy1 = props.new_alert_list.filter((item) =>
item.search_id.includes(term)
);
const no = parseInt(term);
if (isNaN(no)) setItems(dummy);
else setItems(dummy1);
}
Yes you could start from element at index 1, but I think you could also use hasOwnProperty. Something like:
let data = [
2,
{
id: "10000107",
name: "dev name",
},
{
id: "10000106",
name: "alberto",
},
]
data.filter(x => {
if (x.hasOwnProperty("id") && x.hasOwnProperty("name")) {
console.log(x.id, " ", x.name); // if object in array has id and name properties then do stuff...
}
});
.filter() has a second parameter "index", which you can use.
For example:
[1,2,3].filter((element, index) => { return index != 0 });
Source: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
You can pass another parameter index in the filter()
function handleSearch(term) {
const dummy = props.new_alert_list.filter((item, index) =>
index !== 0 ? item.name.toLowerCase().includes(term) : false
);
const dummy1 = props.new_alert_list.filter((item, index) =>
index !== 0 ? item.search_id.includes(term) : false
);
const no = parseInt(term);
if (isNaN(no)) setItems(dummy);
else setItems(dummy1);
Slice the array from index 1 to create a new array to filter from.
function handleSearch(term) {
const dummy = props.new_alert_list.slice(1).filter((item) =>
item.name.toLowerCase().includes(term)
);
const dummy1 = props.new_alert_list.slice(1).filter((item) =>
item.search_id.includes(term)
);
const no = parseInt(term);
if (isNaN(no)) setItems(dummy);
else setItems(dummy1);
}
Alternatively you could access the current index being iterated (the second parameter to filter) and add a condition for non-zero (i.e. truthy) indices.
function handleSearch(term) {
const dummy = props.new_alert_list.filter((item, index) =>
index && item.name.toLowerCase().includes(term)
);
const dummy1 = props.new_alert_list.filter((item, index) =>
index && item.search_id.includes(term)
);
const no = parseInt(term);
if (isNaN(no)) setItems(dummy);
else setItems(dummy1);
}
If the first element is irrelevant in the frontend UI then perhaps you should clear it out before sending in props, or better yet, remove it before saving it into any local component state.
You can just sniff out if the item in the iterator has the properties. If so, then filter
function handleSearch(term) {
setItems(props.new_alert_list
.filter(item =>
(typeof item === "object" &&
(item.hasOwnProperty('name') && item.name.toLowerCase().includes(term.toLowerCase()))
||
(item.hasOwnProperty('search_id') && item.search_id.includes(term))
));
}
let data = [
2, {
search_id: "10000107",
name: "dev name",
},
{
search_id: "10000106",
name: "alberto",
},
{},
{
name: "Joe"
}
]
let term = 'alberto';
let filtered = data.filter(item => (typeof item === "object" && (item.hasOwnProperty('name') && item.name.toLowerCase().includes(term.toLowerCase())) || (item.hasOwnProperty('search_id') && item.search_id.includes(term))));
console.log(filtered);

Remove object items from array of objects and group in node js

I have an array of objects as an input.
var val = [{matnr :'0001',type:'Z0001',price:12.3,location:'Afr'},{matnr :'0001',type:'Z0002',price:12.2,location:'US'},
,{matnr :'0002',type:'Z0003',price:11.2,location:'EU'}]
I need to remove location from each object and group by material.
val = [{
matnr:0001
types :[{type:'Z001',price:12.3},{type:'Z001',price:12.2}]
},
{
matnr:0002
types :[{type:'Z003',price:12.3}]
}
I tried to delete an object from an array and did a group by but seems to be not working. Could you please help
val.forEach((values)=>
Object.keys(values).forEach(function (item) {
if (item !='matnr'||item !='type' || item != price){
delete values[item];
};
})
var grouped = _.groupBy(val, function(val) {
return val.matnr;
});
You can use .reduce() with destructuring to remove the location property and group attributes by matnr by creating an object, where each key is matnr, and each value is an accumulation of properties for that given matnr like so:
const arr = [{matnr:"0001",type:"Z0001",price:12.3,location:"Afr"},{matnr:"0001",type:"Z0002",price:12.2,location:"US"},{matnr:"0002",type:"Z0003",price:11.2,location:"EU"}];
const res = Object.values(arr.reduce((acc, {matnr, type, price}) => {
const {types = []} = acc[matnr] || {};
acc[matnr] = {matnr, types: [...types, {type, price}]};
return acc;
}, Object.create(null)));
console.log(res);
.as-console-wrapper {max-height: 100% !important;}
you can do this without using loadash simply by using the higher-order functions
const cleaned = removeFromList(list).key('location')
const grouped = group(list).by('matnr')
function removeFromList(arr) {
return {
key: key => arr.map(item => {
if (!item[key]) return item
delete item[key]
return item
})
}
}
function group(arr) {
return {
by: groupKey => {
const groupsObj = arr.reduce((groups, item) => {
const groupKeyValue = item[groupKey]
if(!groupKeyValue) return groups
if (!groups[groupKeyValue]){
groups[groupKeyValue] = [item]
return groups
}
groups[groupKeyValue] = [...groups[groupKeyValue], item]
return groups
}, {});
return groupsObj
}
}
}
Note We Prefer the object structures for performance and easy access as developers, so on the group by function we return the grouped object with the materials values as keys and the matches as their values.
Like :
{
0001 : [{type:'Z001',price:12.3},{type:'Z001',price:12.2}]
0002 : [{type:'Z003',price:12.3}]
}
example available here on repl.it

How to re-order an array of objects based on several conditions?

I'm trying to use the Array.prototype.sort() method to reorder an array or objects.
My array of objects may look something like (I have removed irrelevant properties from the real life scenario):
[
{
context: [
{ value: 'hover' }
]
},
{
context: []
},
{
context: [
{ value: 'active' }
]
},
{
context: [
{ value: 'large' }
]
}
]
I need to re-order the objects based on the values contained within the nested objects of the context property.
The conditions are:
If there are no context objects, move to beginning of array
If context object contains a hover value, move to the end of the array
So the above array of 4 objects should be re-ordered from [1, 2, 3, 4] to [2, 3, 4, 1]
I can satisfy the first condition with something like:
rules.sort((a, b) => {
return (a.context.length - b.context.length);
});
...which re-orders the array based on the number of context objects (thus satisfying the first condition), but I can't figure out how to get the second condition satisfied.
I'm able to determine if either a or b arrays contain a context object with a hover value, which feels like a good start, but I'm not sure where to go from here...
rules.sort((a, b) => {
const AIsHover = a.context.some(c => c.value === 'hover');
const BIsHover = b.context.some(c => c.value === 'hover');
return (a.context.length - b.context.length);
});
Any help would be much appreciated! Thanks
You can achieve that simply by distinguishing the cases:
rules.sort((a, b) => {
if (!a.context.length && !b.context.length) {
return 0;
}
if (a.context.length && !b.context.length) {
return 1;
}
if (!a.context.length && b.context.length) {
return -1;
}
if (a.context.some(c => c.value === 'hover') && b.context.some(c => c.value === 'hover')) {
return 0;
}
if (a.context.some(c => c.value === 'hover')) {
return 1;
}
if (b.context.some(c => c.value === 'hover')) {
return -1;
}
return 0;
});

Checking for Differences Between Docs in Array Embedded Within Another Array

I am trying to compare two documents (actually the current and previous version of the same record), to determine if the contents of an array on the root of the documents is different. But what I'm specifically looking for are changes on an embedded array within that root array.
My document structure looks something like this:
{
_id: 1,
name: {
first: "John",
last: "Smith"
},
services: [
{
service: "serviceOne",
// I want to detect differences at this "history" array level
history: [
{
_id: <ObjectId>,
title: value
},
{
_id: <ObjectId>,
title: value
}
]
},
{
service: "serviceTwo",
history: [
{
_id: <ObjectId>,
title: value
},
{
_id: <ObjectId>,
title: value
}
]
},
]
}
How can I check to see if there are differences between the two documents at the level of the "history" array?
Compare the _id and title of all of them:
const compare = cb => (a, b) => a.length === b.length && a.every((el, i) => cb(el, b[i]));
const take = (key, cb) => (a, b) => cb(a[key], b[key]);
const equal = take("services", compare(
take("history", compare(
(a, b) => a._id === b._id && a.title === b.title
))
))(obj, obj2);
Or if the formatting (order of keys) doesn't change between two versions, it can be simplified to:
JSON.stringify(obj) === JSON.stringify(obj2)
You could use this:
function compareObjects(obj1,obj2,reversed){
for(var key in obj1){
if(typeof obj2[key]=="undefined") return false
if(typeof obj1[key] == "object"){
if(!compareObjects(obj1[key],obj2[key])) return false
}
else if(obj1[key]!=obj2[key]) return false
}
return reversed ? true : compareObjects(obj2,obj1,true)
}
via
var new_history = new_document.services.map(service=>service.history)
var old_history = old_document.services.map(service=>service.history)
var are_identical = compareObjects(new_history,old_history)
It will look recursively for differences, regardless of the structure.

Simpler method of filtering array of object of array of objects

I'm trying to filter an array of objects which has objects of array of objects inside. For example, an object in an array would look like this.
list=[...,
{
"types": [
{
"slot": 2,
"type":
{
"url": "http://pokeapi.co/api/v2/type/4/",
"name": "poison"
}
},
{
"slot": 1,
"type":
{
"url": "http://pokeapi.co/api/v2/type/12/",
"name": "grass"
}
}
],
"name": 'bulbasaur'
},...
]
I'm currently filtering the list by its name and the types of objects like this (the this.props.search.search being a string, and the example being an example list of strings that will be adjusted):
let filtered = this.props.pokemons.filter((pokemon)=>{
return pokemon.name.toLowerCase().indexOf(this.props.search.search.toLocaleLowerCase())!==-1;
})
let example = ['fire', 'ice', 'water'];
let filteredx= filtered.filter((pokemon)=>{
return pokemon.types.filter((type)=>{
return example.indexOf(type.type.name)!==-1
}).length>0
})
Is there a method of combining all the filters into one instead of calling
array.filter(...).filter(...)
As in the future, if more filters are added, I'm afraid that it's going to end up looking like
array.filter(...).filter(...).filter(...).filter(...).filter(...)
Any help would be appreciated.
You can combine the two conditions with an &&:
let filteredx = this.props.pokemons.filter(pokemon =>
pokemon.name.toLowerCase().includes(this.props.search.search.toLocaleLowerCase())
&& pokemon.types.some(type => example.includes(type.type.name))
)
Note you can use includes and some in your conditions, and use the expression syntax in your arrow functions (without braces nor return).
You can add more conditions with additional && operators. Make sure to put them in such order that the most simple conditions (that require least work) come first.
If the array is small and perfomance not an issue;
const arryOfPokemons = [{name: 'name1', type: 'type1'}];
function name(pokemon) { return pokemon.name !== 'name' }
function type(pokemon) { return pokemon.type !== 'type' }
const result = [name, type].reduce((result, filterFunc) => result.filter(filterFunc), arryOfPokemons);
otherwise you can try to combine the conditions into the same filter function.
Instead of filtering multiple times, you can combine all the filter conditions in one filter.
Instead of doing this...
let filtered1 = toFilter.filter((element) => {
return condition1;
});
let filtered2 = filtered1.filter((element) => {
return condition2;
});
...
let filteredN = filteredN_1.filter((element) => {
return conditionN;
});
... you can combine the conditions in a single filter:
let filtered = toFilter.filter((element) => {
return condition1 && condition2 && ... && conditionN;
});
If one of the conditions is very long, you can easily abstract it in a separate function. This also makes the code more readable and maintainable.
let filtered = toFilter.filter((element) => {
const condition1 = computeCondition1(arg1, arg2);
const condition2 = computeCondition2(arg1);
...
const condition3 = computeCondition3(arg2, arg3, arg4);
return condition1 && condition2 && ... && conditionN;
});
You could define an object which contains a property for every first level property of your pokemon list you want to test. The value would be a predicate with the "test logic" for this property.
const pokemons = [
{"name":"poke1","types":[{"type":{"name":"poison"}},{"type":{"name":"grass"}}]},
{"name":"poke2","types":[{"type":{"name":"fire"}},{"type":{"name":"grass"}}]},
{"name":"poke3","types":[{"type":{"name":"ice"}},{"type":{"name":"water"}}]},
{"name":"poke4","types":[{"type":{"name":"ice"}},{"type":{"name":"grass"}}]}
];
const filterOptions = {
name: (name) => {
return ["poke1", "poke5"].some(x => x === name);
},
types: (types) => {
return ["ice", "water"].some(t => types.some(x => t === x.type.name));
}
};
function filterList(list, options) {
return list.filter(pokemon => {
return Object.keys(options)
.some(key => {
if (key in pokemon) {
return filterOptions[key](pokemon[key]);
}
});
});
}
const filtered = filterList(pokemons, filterOptions);
filtered.forEach(p => console.log(JSON.stringify(p)));

Categories