Sort JavaScript Array having the array of Object - javascript

Can you please suggest me the best way to sort the below array by the priority based on the name of the section. I am more worried on the time complexity as my array in real consist of 100 000 records.
I am okay also to change the array structure if there any better way to store
[{
id: 'field1',
sections: [{
name: 'Top_Section',
priority: 3
},
{
name: 'Bottom_Section',
priority: 3
}
]
},
{
id: 'field2',
sections: [{
name: 'Top_Section',
priority: 2
},
{
name: 'Bottom_Section',
priority: 4
}
]
},
{
id: 'field3',
sections: [{
name: 'Top_Section',
priority: 1
},
{
name: 'Bottom_Section',
priority: 1
}
]
},
{
id: 'field4',
sections: [{
name: 'Top_Section',
priority: 4
},
{
name: 'Bottom_Section',
priority: 2
}
]
}
];
Like I wanted to sort priority based on the Top_Section so my expected output should be as below
as the field3 is having priority 1 and field2 is having priority 2 etc.
[
{
id: 'field3',
sections: [
{ name: 'Top_Section', priority: 1 },
{ name: 'Bottom_Section', priority: 1 }
]
},
{
id: 'field2',
sections: [
{ name: 'Top_Section', priority: 2 },
{ name: 'Bottom_Section', priority: 4 }
]
},
{
id: 'field1',
sections: [
{ name: 'Top_Section', priority: 3 },
{ name: 'Bottom_Section', priority: 3 }
]
},
{
id: 'field4',
sections: [
{ name: 'Top_Section', priority: 4 },
{ name: 'Bottom_Section', priority: 2 }
]
}
];

I'm assuming here that 'Top_Section' is always on the first position in the sections array.
I'm also assuming that there will be only two types of priority types: 'Top_Section' and 'Bottom_Section'
let list = [{
id: 'field1',
sections: [{
name: 'Top_Section',
priority: 3
},
{
name: 'Bottom_Section',
priority: 3
}
]
},
{
id: 'field2',
sections: [{
name: 'Top_Section',
priority: 2
},
{
name: 'Bottom_Section',
priority: 4
}
]
},
{
id: 'field3',
sections: [{
name: 'Top_Section',
priority: 1
},
{
name: 'Bottom_Section',
priority: 1
}
]
},
{
id: 'field4',
sections: [{
name: 'Top_Section',
priority: 4
},
{
name: 'Bottom_Section',
priority: 2
}
]
}
];
function sortBy(priorityName) {
let priorityPosition = (priorityName == 'Top_Section') ? 0 : 1;
return (a, b) => {
return a['sections'][priorityPosition].priority - b['sections'][priorityPosition].priority;
}
}
console.log( list.sort(sortBy('Top_Section')) );

Let's create a comparator
function compare(a, b) {
var sumA = 0;
var sumB = 0;
for (var section of a.sections) sumA += section.priority;
for (var section of b.sections) sumB += seciton.priority;
return sumB - sumA;
}
arr.sort(compare);
The comparator returns positive if the first parameter is greater, negative if the second parameter is greater and 0 if they are equal. I assumed that the lowest the numeric value of the sum of the priorities, the greater the item is.

Related

search and update within nested array with mongoose

simplified schema of a doc in my Model:
{
ar1: [
{
b: {
ar2: [{ _id: 1, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 2, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 1, value: 5 }],
},
},
];
}
now i want to update all elements of ar2 that have _id equal to 1 so I would obtain:
{
ar1: [
{
b: {
ar2: [{ _id: 1, value: 3 }],
},
},
{
b: {
ar2: [{ _id: 2, value: 2 }],
},
},
{
b: {
ar2: [{ _id: 1, value: 3 }],
},
},
];
}
The following does not work:
Model.updateMany({
'ar1.b.ar2._id' : 1
},{
'ar1.$[].b.ar2.$[].value' : 2
});
any suggestions ?
The idea is that i want to be able the elements in the nested array that obey the query and update them.
You can use $[] combine with $[<identifier>] to do that:
Model.update(
{},
{ $set: { "ar1.$[].b.ar2.$[el].value": 3 } },
{ arrayFilters: [ { "el._id": 1 } ] }
)

Remove duplicate elements of an array, in an object of arrays, dynamically

I have checked other solutions but none fit the criterion of my problem
This solution does not have the ability to dynamically check each node
Problem summarized
I wish to create an algorithm that is able to check an object that has nodes of different data types, for duplicated objects in nodes that are specifically of the datatype array.
I have the following dataset:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
I wish to be able to dynamically check which of the objects (or nodes? and the algo has to recognize that it is an array) has duplicates, and reduce them to be in this form:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 3 }],
};
EDIT
The algorithm needs to be able to handle a dynamic number of nodes (example 1), however , the duplicates will only happen 1 level down (Thanks for pointing out).
example 1 (there is 1 less node here ) :
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
};
Here is my proposed solution to remove duplicate elements from any array in the task object:
const uniq = array => {
const map = {};
const result = [];
for (let i = 0; i < array.length; i++) {
// since elements can be objects, need to do a deep comparison.
const element = JSON.stringify(array[i]);
if (map[element] === undefined) {
map[element] = true;
result.push(array[i]);
}
}
return result;
}
const task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
for (const key in task) {
if (Array.isArray(task[key])) {
task[key] = uniq(task[key])
}
}
console.log('deduped:', task);

Compare and reduce complex array of objects

I have a ``dataset which is an array of objects for some items in a database that has the details of how long it will take in estimatedDays for a specific item to be shipped:
items : [
{
id: '1'
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3,
},
{
id: 'TWODAY',
estimatedDays: 2,
},
{
id: 'NEXTDAY',
estimatedDays: 1,
},
]
},
{
id: '2'
// same shipping data as above but standard shipping will take 4 estimatedDays
},
{
id: '3'
// same shipping data as above but TWODAY shipping will take 3 estimatedDays
},
]
I am wondering if there is a reduce function that could compare each shippingMethod.id in each item and return a new array back only where shippingMethod.estimatedDays is greatest compared to all items.
So the end array would be an array of objects with (in this case) 3 shipping methods: STANDARD, TWODAY, and NEXTDAY.
Here you go with the reduce method,
reduce
var items = [
{
id: '1',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3
},
{
id: 'TWODAY',
estimatedDays: 2
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
{
id: '2',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 4
},
{
id: 'TWODAY',
estimatedDays: 2
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
{
id: '3',
shippingMethods: [
{
id: 'STANDARD',
estimatedDays: 3
},
{
id: 'TWODAY',
estimatedDays: 3
},
{
id: 'NEXTDAY',
estimatedDays: 1
},
]
},
];
var outItems = items.reduce(function(accu, curr){
if(curr.shippingMethods) {
if(accu.length > 0) {
for(var i = 0; i < curr.shippingMethods.length; i++) {
var current = curr.shippingMethods[i];
if(accu[i].id === current.id && accu[i].estimatedDays < current.estimatedDays) {
accu[i] = current;
}
}
} else {
accu = curr.shippingMethods;
}
}
return accu;
}, []);
console.log(outItems);

How union arrays with validate only one property

Joining of Arrays.
I'm in need of running a "Join Array" objects, but, I need duplicated objects to be removed, see:
Example
var objArray1 = [
{ Id: 1, Name: 'João', Order: 2 },
{ Id: 2, Name: 'Pedro', Order: 5 }
];
var objArray2 = [
{ Id: 2, Name: 'Pedro', Order: 6 },
{ Id: 3, Name: 'Manoel', Order: 9 }
];
Actual code:
var result = _.union(objArray1,objArray2);
=> [
{ Id: 1, Name: 'João', Order: 2 },
{ Id: 2, Name: 'Pedro', Order: 5 },
{ Id: 2, Name: 'Pedro', Order: 6 },
{ Id: 3, Name: 'Manoel', Order: 9 }
];
I need this result:
[
{ Id: 1, Name: 'João', Order: 2 },
{ Id: 2, Name: 'Pedro', Order: 5 },
{ Id: 3, Name: 'Manoel', Order: 9 }
];
Basic I need join arrays with filter the one property, I need is possible with For but I would like a better solution
use underscore unique function as follows
var result = _.uniq(_.union(objArray1, objArray2), false, function(item){ return item.Id; });
not 100% sure if the false should be true
or, as seems to be a trend on SO - the sexy ES2015 version
var result = _.uniq(_.union(objArray1, objArray2), false, item => item.Id);

Elasticsearch multi field fuzzy search not returning exact match first

I am performing a fuzzy elasticsearch query on 'text' and 'keywords' fields. I have two documents in elasticsearch, one with 'text' "testPhone 5" and the other "testPhone 4s". When I perform a fuzzy query with "testPhone 5", I am seeing that both documents are being given the exact same score value. Why is this occurring?
Extra info: I am indexing documents using the 'uax_url_email' tokenizer and 'lowercase' filter.
This is the query I am making:
{
query : {
bool: {
// match one or the other fuzzy query
should: [
{
fuzzy: {
text: {
min_similarity: 0.4,
value: 'testphone 5',
prefix_length: 0,
boost: 5,
}
}
},
{
fuzzy: {
keywords: {
min_similarity: 0.4,
value: 'testphone 5',
prefix_length: 0,
boost: 1,
}
}
}
]
}
},
sort: [
'_score'
],
explain: true
}
This is the result:
{ max_score: 0.47213298,
total: 2,
hits:
[ { _index: 'test',
_shard: 0,
_id: '51fbf95f82e89ae8c300002c',
_node: '0Mtfzbe1RDinU71Ordx-Ag',
_source:
{ next: { id: '51fbf95f82e89ae8c3000027' },
cards: [ '51fbf95f82e89ae8c3000027', [length]: 1 ],
other: false,
_id: '51fbf95f82e89ae8c300002c',
category: '51fbf95f82e89ae8c300002b',
image: 'https://s3.amazonaws.com/sold_category_icons/Smartphones.png',
text: 'testPhone 5',
keywords: [ [length]: 0 ],
__v: 0 },
_type: 'productgroup',
_explanation:
{ details:
[ { details:
[ { details:
[ { details:
[ { details:
[ { value: 3.8888888, description: 'boost' },
{ value: 1.5108256,
description: 'idf(docFreq=2, maxDocs=5)' },
{ value: 0.17020021,
description: 'queryNorm' },
[length]: 3 ],
value: 0.99999994,
description: 'queryWeight, product of:' },
{ details:
[ { details:
[ { value: 1, description: 'termFreq=1.0' },
[length]: 1 ],
value: 1,
description: 'tf(freq=1.0), with freq of:' },
{ value: 1.5108256,
description: 'idf(docFreq=2, maxDocs=5)' },
{ value: 0.625,
description: 'fieldNorm(doc=0)' },
[length]: 3 ],
value: 0.944266,
description: 'fieldWeight in 0, product of:' },
[length]: 2 ],
value: 0.94426596,
description: 'score(doc=0,freq=1.0 = termFreq=1.0\n), product of:' },
[length]: 1 ],
value: 0.94426596,
description: 'weight(text:testphone^3.8888888 in 0) [PerFieldSimilarity], result of:' },
[length]: 1 ],
value: 0.94426596,
description: 'sum of:' },
{ value: 0.5, description: 'coord(1/2)' },
[length]: 2 ],
value: 0.47213298,
description: 'product of:' },
_score: 0.47213298 },
{ _index: 'test',
_shard: 4,
_id: '51fbf95f82e89ae8c300002d',
_node: '0Mtfzbe1RDinU71Ordx-Ag',
_source:
{ next: { id: '51fbf95f82e89ae8c3000027' },
cards: [ '51fbf95f82e89ae8c3000029', [length]: 1 ],
other: false,
_id: '51fbf95f82e89ae8c300002d',
category: '51fbf95f82e89ae8c300002b',
image: 'https://s3.amazonaws.com/sold_category_icons/Smartphones.png',
text: 'testPhone 4s',
keywords: [ 'apple', [length]: 1 ],
__v: 0 },
_type: 'productgroup',
_explanation:
{ details:
[ { details:
[ { details:
[ { details:
[ { details:
[ { value: 3.8888888, description: 'boost' },
{ value: 1.5108256,
description: 'idf(docFreq=2, maxDocs=5)' },
{ value: 0.17020021,
description: 'queryNorm' },
[length]: 3 ],
value: 0.99999994,
description: 'queryWeight, product of:' },
{ details:
[ { details:
[ { value: 1, description: 'termFreq=1.0' },
[length]: 1 ],
value: 1,
description: 'tf(freq=1.0), with freq of:' },
{ value: 1.5108256,
description: 'idf(docFreq=2, maxDocs=5)' },
{ value: 0.625,
description: 'fieldNorm(doc=0)' },
[length]: 3 ],
value: 0.944266,
description: 'fieldWeight in 0, product of:' },
[length]: 2 ],
value: 0.94426596,
description: 'score(doc=0,freq=1.0 = termFreq=1.0\n), product of:' },
[length]: 1 ],
value: 0.94426596,
description: 'weight(text:testphone^3.8888888 in 0) [PerFieldSimilarity], result of:' },
[length]: 1 ],
value: 0.94426596,
description: 'sum of:' },
{ value: 0.5, description: 'coord(1/2)' },
[length]: 2 ],
value: 0.47213298,
description: 'product of:' },
_score: 0.47213298 },
[length]: 2 ] }
Fuzzy queries are not analyzed but the field is so your search for testphone 5 with a distance of 0.4 yields the analyzed term testphone for both documents and that term is used to further filter down the results
description: 'weight(text:testphone^3.8888888 in 0) [PerFieldSimilarity], result of:' },
See also #imotov excellent answer here:
ElasticSearch's Fuzzy Query
You can see how exactly a string will be tokenized using the _analyze API
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-analyze.html
i.e
http://localhost:9200/prefix_test/_analyze?field=text&text=testphone+5
will return:
{
"tokens": [
{
"token": "testphone",
"start_offset": 0,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "5",
"start_offset": 10,
"end_offset": 11,
"type": "<NUM>",
"position": 2
}
]
}
So even if you index the value testphone sammsung a fuzzy query for "testphone samsunk" won't yield anything where as just samsunk will.
You may get better results by not analyzing (or using the keyword analyzer) the field.
If you want to have different analysis on a single field you can use the multi_field construct.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-multi-field-type.html
I ran into this issue myself recently.
I can't tell you exactly why it is happening, but I CAN tell you how I fixed it:
I ran 2 queries over the same field, one with an exact match, and then the exact same query on the same field with fuzzy matches enabled and a lower boost.
That made sure that my exact matches always ended higher then the fuzzy matches.
P.S.
I think they're scored equal because, because of the fuzziness, the both match and ES doesn't care that one is an exact match as long as the both match, but this is pure theory crafting on my end since i'm not intimately familiar with the scoring algorithm.

Categories

Resources