Remove Array Json object elements - node.js

Here I have two arrays
var arry1 = [{id:1,name:"muni"},{id:2,name:"Anji"}, {id:3,name:"vinod"},{id:4,name:"anil"}];
var arry2 = [{id:3},{id:1}];
I want the following results
arry1= [{id:2,name:"Anji"},{id:4,name:"anil"}]
Should be remove second selected elements in first array

You can use Array.filter to remove any element that is present in arry2. We can create a Set of id elements to filter out, this will be more efficient for larger arrays:
var arry1 = [{id:1,name:"muni"},{id:2,name:"Anji"}, {id:3,name:"vinod"},{id:4,name:"anil"}];
var arry2 = [{id:3},{id:1}];
// Filter out any elements in arry1 that are also present in arry2, first create a Set of IDs to filter
const idsToFilter = new Set(arry2.map(el => el.id));
const result = arry1.filter(el => !idsToFilter.has(el.id));
console.log("Result:", result)

While removing from an array, you should iterate backwards over it.
for (let i = arry1.length - 1; i >=0; i--) {
...
}
This ensures that no elements are skipped after an element is removed. See also this other question for more info on this.
Now for each element of arry1 we want to check whether it should be removed.
let idsToRemove = arry2.map(e => e.id); // [3, 1]
for (let i = arry1.length - 1; i >=0; i--) {
if (idsToRemove.includes(arry1[i].id) {
// it should be removed
arry1.splice(i, 1);
}
}
Something like the above should then work for your problem. For easier understanding of the code, I first mapped arry2 to only the IDs, but of course you can also use another loop to see whether there is a match. The most important take-away is that to safely remove from an array while iterating it, you need to iterate from the last to the first element.

Try this it will work, here filter will filter out only those array element which doesn't exist in arry2
var myArray = arry1.filter(ar => !arry2.find(el => (el.id === ar.id) ))

Related

How to check if a list exist inside another list

So I have a list a that contain the string "ab" and another list b that contain a list that contain the string "ab". So it look something like this:
var a = ["ab"]
var b = [["ab"]]
How can I check if a is in b. I have try using b.includes(a) that result in a false and I also have try b.indexOf(a) which also return false. The way that I currently use is this:
var flag = false
var a = ["ab"]
var b = [["ab"]]
b.forEach((i) => {
if (i.join("") == a.join("")) flag = true
})
console.log(flag)
Is there like a shorter way?
Thanks y'all.
Little trick for you. You can compare two array if you use toString() method.
const a = ["ab"];
const b = [["ab"]];
const result = b.some(p => p.toString().includes(a));
console.log(result);
Not quiet sure what exactly you want to check but here are 2 examples:
var a = ["ab"];
var b = [["ab"]];
var flag = false;
//Example 1: search for "ab" in the nested array
b.forEach(el=>{
el.forEach(innerEl=>{
if(innerEl === "ab") flag = true;
});
});
console.log(`Result 1 ${flag}`);
//Example 1: seach for the exact array ["ab"]
b.forEach(el=>{
if(el == a)flag = true;
});
console.log(`Result 2 ${flag}`);
If you have references you can do as follows:
var a = ["ab"];
var b = [a];
b.includes(a); // true
Otherwise you need to convert those arrays to strings and compare those as others suggested or compare inside values of those nested arrays one by one because:
['a'] != ['a'] // this is true because those are 2 different arrays

Node - Test if string contain element of array replace him by random element of same array (synonym)

I want to change each word that matches the synonym list randomly by another synonym or itself (to randomly keep this keyword).
I test if a string (input) contains one element of an array (words). If it's true, I want to randomly replace this with the element of this same list.
var input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
words_synonym = ["amazing", "formidable", "great", "smart"];
// first condition --> true if "input" contain one element of "words_synonym"
input = input.toLowerCase();
console.log(words_synonym.some(word => input.includes(word)));
after, I want to replace the "element" that validated the condition with a random element of the same array (words_synonym).
But I can't select this element. I have just true or false
var random_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))]
input = input.replace(element, random_word, 0)
thanks
The way you have it right now, you're checking if any of the synonyms match any of the words (via words_synonym.some(word => input.includes(word))). In order to do what you want, you'll need both the position of the target word and the new word, neither of which you have now. To do this, you'll want to break apart your nested loops.
The code words_synonym.some(word => input.includes(word)) is equivalent to:
let has_synonym = false;
for (word of words_synonym) { // this is a loop
if (input.includes(word)) { // this is also a loop
has_synonym = true;
break;
}
}
console.log(has_synonym);
So to fix your main issue, just replace includes with indexOf.
To handle the case of replacing all of the tokens, I would suggest keeping track of the token you have replaced outside of the loop, otherwise you end up replacing each token many times which may become very expensive. To do this, just keep track of your starting position outside of the loop and increment it with the end index of the replacement word. indexOf already takes a start argument for exactly this use case!
const input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
const words_synonym = ["amazing", "formidable", "great", "smart"];
let output = input;
let start = 0; // index of the end of the last replaced token
for (word of words_synonym) {
let index = output.indexOf(word, start);
while (index >= 0) {
const new_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))];
output = output.substr(0, index) + new_word + output.substr(index + word.length, output.length);
start = index + new_word.length + 1; // increment the start
index = output.indexOf(word, start);
}
}
console.log("input: ", input);
console.log("output: ", output);
You can use method find:
words_synonym.find(word => input.includes(word))
Which returns
The value of the first element in the array that satisfies the
provided testing function. Otherwise, undefined is returned.
from docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
i have modify answer of dantiston and i have include a loop in order to change all the word match "words_synonym".
But there is a problem. The program don't check all the word of "words_synonym" but only the first with indexof.
var input = "This is an amazing text blob where this word amazing is replaced by a random word from list_of_words. Isn't this amazing!";
words_synonym = ["amazing", "formidable", "great", "smart"];
let output = input;
for (word of words_synonym) {
let index = output.indexOf(word);
if (index >= 0) {
console.log(word);
var indexes = [], i = -1;
while ((i = output.indexOf(word, i+1)) != -1){
index=output.indexOf(word, i);
var new_word = words_synonym[Math.floor(Math.random() * (words_synonym.length))];
output = output.substr(0, index) + new_word + output.substr(index + word.length, output.length);
}
}
}
console.log("input: ", input);
console.log("output: ", output);

I cannot find out why this code keeps skipping a loop

Some background on what is going on:
We are processing addresses into standardized forms, this is the code to take addresses scored by how many components found and then rescore them using a levenshtein algorithm across similar post codes
The scores are how many components were found in that address divided by the number missed, to return a ratio
The input data, scoreDict, is a dictionary containing arrays of arrays. The first set of arrays is the scores, so there are 12 arrays because there are 12 scores in this file (it adjusts by file). There are then however many addresses fit that score in their own separate arrays stored in that. Don't ask me why I'm doing it that way, my brain is dead
The code correctly goes through each score array and each one is properly filled with the unique elements that make it up. It is not short by any amount, nothing is duplicated, I have checked
When we hit the score that is -1 (this goes to any address where it doesn't fit in some rule so we can't use its post code to find components so no components are found) the loop specifically ONLY DOES EVERY OTHER ADDRESS IN THIS SCORE ARRAY
It doesn't do this to any other score array, I have checked
I have tried changing the number to something else like 99, same issue except one LESS address got rescored, and the rest stayed at the original failing score of 99
I am going insane, can anyone find where in this loop something may be going wrong to cause it to only do every other line. The index counter of line and sc come through in the correct order and do not skip over. I have checked
I am sorry this is not professional, I have been at this one loop for 5 hours
Rescore: function Rescore(scoreDict) {
let tempInc = 0;
//Loop through all scores stored in scoreDict
for (var line in scoreDict) {
let addUpdate = "";
//Loop through each line stored by score
for (var sc in scoreDict[line.toString()]) {
console.log(scoreDict[line.toString()].length);
let possCodes = new Array();
const curLine = scoreDict[line.toString()][sc];
console.log(sc);
const curScore = curLine[1].split(',')[curLine[1].split(',').length-1];
switch (true) {
case curScore == -1:
let postCode = (new RegExp('([A-PR-UWYZ][A-HK-Y]?[0-9][A-Z0-9]?[ ]?[0-9][ABD-HJLNP-UW-Z]{2})', 'i')).exec(curLine[1].replace(/\\n/g, ','));
let areaCode;
//if (curLine.split(',')[curLine.split(',').length-2].includes("REFERENCE")) {
if ((postCode = (new RegExp('(([A-Z][A-Z]?[0-9][A-Z0-9]?(?=[ ]?[0-9][A-Z]{2}))|[0-9]{5})', 'i').exec(postCode))) !== null) {
for (const code in Object.keys(addProper)) {
leven.LoadWords(postCode[0], Object.keys(addProper)[code]);
if (leven.distance < 2) {
//Weight will have adjustment algorithms based on other factors
let weight = 1;
//Add all codes that are close to the same to a temp array
possCodes.push(postCode.input.replace(postCode[0], Object.keys(addProper)[code]).split(',')[0] + "(|W|)" + (leven.distance/weight));
}
}
let highScore = 0;
let candidates = new Array();
//Use the component script from cityprocess to rescore
for (var i=0;i<possCodes.length;i++) {
postValid.add([curLine[1].split(',').slice(0,curLine[1].split(',').length-2) + '(|S|)' + possCodes[i].split("(|W|)")[0]]);
if (postValid.addChunk[0].split('(|S|)')[postValid.addChunk[0].split('(|S|)').length-1] > highScore) {
candidates = new Array();
highScore = postValid.addChunk[0].split('(|S|)')[postValid.addChunk[0].split('(|S|)').length-1];
candidates.push(postValid.addChunk[0]);
} else if (postValid.addChunk[0].split('(|S|)')[postValid.addChunk[0].split('(|S|)').length-1] == highScore) {
candidates.push(postValid.addChunk[0]);
}
}
score.Rescore(curLine, sc, candidates[0]);
}
//} else if (curLine.split(',')[curLine.split(',').length-2].contains("AREA")) {
// leven.LoadWords();
//}
break;
case curScore > 0:
//console.log("That's a pretty good score mate");
break;
}
//console.log(line + ": " + scoreDict[line].length);
}
}
console.log(tempInc)
score.ScoreWrite(score.scoreDict);
}
The issue was that I was calling the loop on the array I was editing, so as each element got removed from the array (rescored and moved into a separate array) it got shorter by that element, resulting in an issue that when the first element was rescored and removed, and then we moved onto the second index which was now the third element, because everything shifted up by 1 index
I fixed it by having it simply enter an empty array for each removed element, so everything kept its index and the array kept its length, and then clear the empty values at a later time in the code

Javascript ES6 - Node Js - Associative Array - Objects use - wrong default order

I have a problem trying to use associative arrays/objects in node, I have the following code and I want to get the same order I use when i inserted elements.
var aa = []
aa[0] = 1
aa['second'] = 'pep'
aa['third'] = 'rob'
aa[4] = 2
for (var pos in aa) console.log (aa[pos])
But internally node put/sort first the numbers.
Look real execution :
1
2
pep
rob
I have created a parallel dynamic structure to solve this problem, but I'd like to ask for another solution or idea to get this target.
Regards.
Ricardo.
First of all, I'd recommend to use dictionary but not array, for dynamic keys:
var aa = {};
Elements are listed as its default order. You could check its default order with:
var keys = Object.keys(aa);
for (var i = 0; i < keys.length; i++) {
console.log(keys[i]);
}
If the default order is needed as the same order when inserting elements, try this to save the inserting order in another array:
var aa = {};
var keys = [];
aa[0] = 1
keys.push(0);
aa['second'] = 'pep'
keys.push('second');
aa['third'] = 'rob'
keys.push('third');
aa[4] = 2
keys.push(4);
for (var i = 0; i < keys.length; i++) {
console.log(aa[keys[i]]);
}
You may also want to give some ES6 features a try. Given you want to store data in a hash-like data structure that preserves the order I would recommend to give Map a try:
var map = new Map();
map.set(0, 1);
map.set('second', 'pep');
map.set('third', 'rob');
map.set(4, 2);
for (var [key, value] of map) {
console.log(key, value);
}
map.forEach(function (value, key) {
console.log(key, value);
});
nodejs arrays are just objects with numbers as keys and some added functions to their prototype. Also assoc. arrays are usually two arrays with values hinged together via a common index. for example:
let a = [1,2,3];
let b = ["one","two","three"];
also try to get away from looking through arrays with for loops. use the plethora of functions available to you via the prototype. for loops also iterate through enumerable properties on the objects prototype, so a for loop would incorrectly also iterate through that.

Linq to split/analyse substrings

I have got a List of strings like:
String1
String1.String2
String1.String2.String3
Other1
Other1.Other2
Test1
Stuff1.Stuff1
Text1.Text2.Text3
Folder1.Folder2.FolderA
Folder1.Folder2.FolderB
Folder1.Folder2.FolderB.FolderC
Now I would like to group this into:
String1.String2.String3
Other1.Other2
Test1
Stuff1.Stuff1
Text1.Text2.Text3
Folder1.Folder2.FolderA
Folder1.Folder2.FolderB.FolderC
If
"String1" is in the next item "String1.String2" I will ignore the first one
and if the second item is in the third I will only take the third "String1.String2.String3"
and so on (n items). The string is structured like a node/path and could be split by a dot.
As you can see for the Folder example Folder2 has got two different Subfolder items so I would need both strings.
Do you know how to handle this with Linq? I would prefer VB.Net but C# is also ok.
Regards Athu
Dim r = input.Where(Function(e, i) i = input.Count - 1 OrElse Not input(i + 1).StartsWith(e + ".")).ToList()
Condition within Where method checks if element is last from input or is not followed by element, that contains current one.
That solution uses the fact, that input is List(Of String), so Count and input(i+1) are available on O(1) time.
LINQ isn't really the correct approach here, because you need to access more than one item at a time.
I would go with something like this:
public static IEnumerable<string> Filter(this IEnumerable<string> source)
{
string previous = null;
foreach(var current in source)
{
if(previous != null && !current.Contains(previous))
yield return previous;
previous = current;
}
yield return previous;
}
Usage:
var result = strings.Filter();
Pretty simple one. Try this:
var lst = new List<string> { /*...*/ };
var sorted =
from item in lst
where lst.Last() == item || !lst[lst.IndexOf(item) + 1].Contains(item)
select item;
the following simple line can do the trick, I'm not sure about the performance cost through
List<string> someStuff = new List<string>();
//Code to the strings here, code not added for brewity
IEnumerable<string> result = someStuff.Where(s => someStuff.Count(x => x.StartsWith(s)) == 1);

Resources