I have an array of array.
m = [[-100,100], [-100,-100], [-100,-100], [-100,100]]
And I want to remove the duplicates. I tried
aa = [...new Set(m)];
// and
let chkdup = (arr, tar) => tar.every(v => arr.includes(v))`.
But I can't remove the duplicates.
In Python, I can easily check this [-100,100] in m. But I don't know the function in JS. includes is not working for this case.
This happens because [-100, 100] != [-100, 100]. What you can do is convert the arrays into strings, and compare the strings instead, with JSON.stringify.
let m = [[-100,100], [-100,-100], [-100,-100], [-100,100]]
m = m.map(item => JSON.stringify(item).trim()) // Stringify everything (remove leading white space)
m = [...new Set(m)] // Convert to array getting rid of duplicates
m = m.map(item => JSON.parse(item)) // Parse it
Note that this is not very efficient (The interpreter has to convert into a string and parse the object again) but it is the simpliest solution. What it does is it checks if the JSON string of 2 Objects is equal an will not work with your own classes.
The reason why new Set doesn't work well is because in JavaScript, arrays with the same values are not equal. Try: console.log([-100,100] == [-100,100]); will return false. Please refer to this post if you simply wants to compare between arrays.
A workaround is to convert subarrays into strings, and use Set to deduplicate:
const arr = [
[-100, 100],
[-100, -100],
[-100, -100],
[-100, 100]
];
const setArray = new Set(arr.map(x => JSON.stringify(x)));
const result = [...setArray].map(x => JSON.parse(x));
console.log(result);
Using lodash uniq is a simple alternative.
You can simply do this thing using javascript Set , map then parse the value. For more information Map with Set
m = [[-100,100], [-100,-100], [-100,-100], [-100,100]];
result = Array.from(new Set(m.map(JSON.stringify)), JSON.parse);
console.log(t);
You can stringify your arrays using .map() with JSON.stringify(), and enter that into a set. Since you now have an array of strings, the set will remove the duplicates as it can check for equality correctly. You can then use Array.from with a mapping function of JSON.parse to convert it back into an array of arrays:
const m = [[-100,100], [-100,-100], [-100,-100], [-100,100]];
const res = Array.from(new Set(m.map(JSON.stringify)), JSON.parse);
console.log(res);
Related
I know that if there is an array of values it must be used this approach:
console.log(['joe', 'jane', 'mary'].includes('jane')); // true
But in case of an array of arrays, is there a short way to do it? Without other computations between.
For this input:
[['jane'],['joe'],['mary']]
You can use flat method to flatten the array. For more neted array, you can also mention depth like flat(depth)
let arr = [["jane"],["joe"],["mary"]];
arr.flat().includes('jane'); //true
You can easily achieve this result using some
arr.some((a) => a.includes("jane"))
const arr = [
["jane"],
["joe"],
["mary"]
];
const arr2 = [
["joe"],
["mary"]
];
console.log(arr.some((a) => a.includes("jane")));
console.log(arr2.some((a) => a.includes("jane")));
it can also be done by first flattening the 2d arrays in 1 d aaray and then using includes to find whether the array contains the element or not
var arr = [['jane'],['joe'],['marry']]
var newarr=[].concat(...arr)
var v=newarr.includes('jane')
console.log(v)
Why reverse() doesn't work if my array have elements with string as a key.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
console.log(myArray)
console.log(myArray.reverse())
Both returns the same result.
How can I change it to make it work?
DEMO: https://www.w3schools.com/code/tryit.asp?filename=GG4PXCHZ4VUD
.reverse() is a function of arrays, where elements are indexed by their position. Your code is not adding elements to the array, but rather adding properties on the array object. This works and the properties can be accessed, but reversing does nothing as these are not elements. The array is still of 0 length.
You will have to either:
Make myArray an object of a different type. In this case, reverse will still not work, and you will have to write code to sort manually. Other answers have provided some guidance as to how to achieve this
Add your elements to the array using push() or numeric indices, in which case you'll lose the string indices but can use array sorting methods such as .reverse()
While numbers have an intrinsic ordering, object property keys follow different rules. If you want to reverse a string-indexed object, consider writing a function to insert objects to a new Map in reverse order.
Arrays values are only accessible by index.
myArray[0] = 100;
myArray[1] = 200;
console.log(myArray) // [100, 200]
console.log(myArray.reverse()) // [200, 100]
You can store values by keys in objects.
var myObject = {};
myObject["test"] = 100;
myObject["test2"] = 200;
console.log(myObject) // {test: 100, test2: 200}
That said, you can reverse an object by doing this:
Object.entries(myObject).reverse().reduce((a, b) => {
a[b[0]] = b[1];
return a
},{})
Since you do not actually need any array methods, it would be better to simply use an object instead.
You can create a new reversed array by looping over Object.keys() backwards. See the code in action here.
var myArray = [];
myArray["test"] = 100;
myArray["test2"] = 200;
function reverseAssociative(arr){
const keys = Object.keys(arr);
const res = [];
for(let i = keys.length - 1; i >= 0; i--){
res[keys[i]] = arr[keys[i]];
}
return res;
}
const res = reverseAssociative(myArray);
for(const key in res){
console.log(key, res[key]);
}
You can simplify it by using reduce on Object.entries after reversing. See the code in action here.
myArray = Object.entries(myArray).reverse().reduce((acc,[key,val])=>(acc[key]=val,acc),[])
I have two 2D arrays with identical elements but in a different order. I want to filter one taking into account if it already exists in the second array.
Examples of both arrays:
const firstArray = [['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['43452341','2020-4-28']] // there are like 40 arrays inside, not sorted
const secondArray = [['34347896', '2020´4-30'],['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['45892916','2020-4-28']] // there are like 300 arrays inside, not sorted
I want to eliminate the arrays of the "secondArray" that have the first index repeated in the "firstArray".
secondArray =[['34347896', '2020´4-30'], ['45892916','2020-4-28']]
I tried several things, I know that the most useful action is to use .reduce but it seems that I cannot make it work.
const notPosted = secondArray.reduce((a, b) => {
if (!firstArray[a[0]]) a.different.push(b);
return a;
}, {different: []});
Thanks!
I dont know which one is faster:
const arr1 = [['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['43452341','2020-4-28']]
const arr2 = [['34347896', '2020´4-30'],['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['45892916','2020-4-28']];
//First solution:
console.log("1) ",arr2.filter(e=>!arr1.some(e2=>JSON.stringify(e2)==JSON.stringify(e))))
//Second:
console.log("2) ",arr2.filter(e=>!arr1.some(e2=>e[0]==e2[0]&&e[1]==e2[1])))
You could convert your 2D array into an object with the zero index of each nested array being the key, and the first index being the value. (i.e. you already have your array in the perfect form for this [[key, val], [key, val], ...])
This is easy with Object.fromEntries(firstArray);
Then you call a simple filter function on your second array and return only those that have a key that is not in the object (lookups of keys in an object are fast - hash tables)
// there are like 40 arrays inside, not sorted
const firstArray = [['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['43452341','2020-4-28']]
// there are like 300 arrays inside, not sorted
const secondArray = [['34347896', '2020´4-30'],['45614726','2020-4-28'],['45610125','2020-4-28'],['45880944','2020-4-28'],['45892916','2020-4-28']];
const firstObj = Object.fromEntries(firstArray);
const secondFiltered = secondArray.filter(([key,val]) => !firstObj.hasOwnProperty(key));
console.log(secondFiltered);
var strArr = ["[1,2,3,4]","[1,2,3,4"]];
var arr1 = strArr[0].match(/\d+/g).map(Number);
I know that the map() method creates a new array with the results of calling a provided function on every element in the calling array. Here as Number is a wrapper object I am not able to understand what's going on.
What I understood is that if I console log removing the map method I get an array of strings whereas including the map method I get an array of numbers.I would like to know how map is able to take each string and converting to number.
var arr1 = strArr[0].match(/\d+/g).map(Number);
is equivalent to
var arr1 = strArr[0].match(/\d+/g).map((str, ind, arr) => Number(str, ind, arr));
The reason Number works despite passing extra arguments in is because it ignores everything but the first argument. You cannot expect every function to behave accordingly, since not all functions ignore everything but the first argument, but in this case it is a convenient shortcut. Another neat example that works well is converting truthy and falsy values to booleans:
var arrBool = arrAny.map(Boolean);
strArr[0] //selects the first string. "[1,2,3,4]"
.match(/\d+/g) // give an array of all continuos strings of digits. ['1','2','3','4']
.map(Number) // Calls Number on each value in the array (casting it to a number)
// and returns the array of results. [1,2,3,4]
//
// Keep in mind Number(val) attempts to create a Number from
// what ever is passed to it. If it is a string itll
// try to convert the string to a numerical value.
Its a complicated way of parsing a string containing an array literal. Seems like a complicated way of doing:
JSON.parse(strArr[0])
but without more context I cant tell you if its bad programming or if there is a good reason for it.
Actually Number is a function, and it can easily be proved:
typeof Number === 'function'; // true
Hence it can be used in any case where functions are expected (and naturally it can be passed as an argument):
Number("5") === 5; // true
let arr = ["442", "452h", "424", "foo", "bar", "31", "35"];
arr = arr.filter(x => !isNaN(Number(x))); // ["442", "424", "31", "35"]
And finally:
const arr2 = arr.map(x => Number(x)); // [442, 424, 31, 35]
const arr3 = arr.map(Number); // [442, 424, 31, 35] – the same result
UPD: To make it look extra-easy, let us compose a simple function that does exactly the same thing as the inbuilt Number function (converts values of other types to the number type):
const toNumber = x => +x;
// OR: function toNumber(x) { return +x; }
const arr4 = arr.map(toNumber); // also [442, 424, 31, 35]
You are passing in the Number object/function and converting a single thing that matches that regex in strArr into a Number
It's the same as doing Number(x), where x is an index in the array.
For example,
var num1 = "1";
var num2 = "2";
var result = Number(num1) + Number(num2); // This will work since they are both numbers now.
So calling map on the strings in the array just converts them that specific index into a Number object.
Learn more about Numbers here.
Set seems like a nice way to create Arrays with guaranteed unique elements, but it does not expose any good way to get properties, except for generator [Set].values, which is called in an awkward way of mySet.values.next().
This would have been ok, if you could call map and similar functions on Sets. But you cannot do that, as well.
I've tried Array.from, but seems to be converting only array-like (NodeList and TypedArrays ?) objects to Array. Another try: Object.keys does not work for Sets, and Set.prototype does not have similar static method.
So, the question: Is there any convenient inbuilt method for creating an Array with values of a given Set ? (Order of element does not really matter).
if no such option exists, then maybe there is a nice idiomatic one-liner for doing that ? like, using for...of, or similar ?
if no such option exists, then maybe there is a nice idiomatic
one-liner for doing that ? like, using for...of, or similar ?
Indeed, there are several ways to convert a Set to an Array:
Using Array.from:
Note: safer for TypeScript.
const array = Array.from(mySet);
Simply spreading the Set out in an array:
Note: Spreading a Set has issues when compiled with TypeScript (See issue #8856). It's safer to use Array.from above instead.
const array = [...mySet];
The old-fashioned way, iterating and pushing to a new array (Sets do have forEach):
const array = [];
mySet.forEach(v => array.push(v));
Previously, using the non-standard, and now deprecated array comprehension syntax:
const array = [v for (v of mySet)];
via https://speakerdeck.com/anguscroll/es6-uncensored by Angus Croll
It turns out, we can use spread operator:
var myArr = [...mySet];
Or, alternatively, use Array.from:
var myArr = Array.from(mySet);
Assuming you are just using Set temporarily to get unique values in an array and then converting back to an Array, try using this:
_.uniq([])
This relies on using underscore or lo-dash.
Perhaps to late to the party, but you could just do the following:
const set = new Set(['a', 'b']);
const values = set.values();
const array = Array.from(values);
This should work without problems in browsers that have support for ES6 or if you have a shim that correctly polyfills the above functionality.
Edit: Today you can just use what #c69 suggests:
const set = new Set(['a', 'b']);
const array = [...set]; // or Array.from(set)
Use spread Operator to get your desired result
var arrayFromSet = [...set];
The code below creates a set from an array and then, using the ... operator.
var arr=[1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,];
var set=new Set(arr);
let setarr=[...set];
console.log(setarr);
SIMPLEST ANSWER
just spread the set inside []
let mySet = new Set()
mySet.add(1)
mySet.add(5)
mySet.add(5)
let arr = [...mySet ]
Result: [1,5]
In my case the solution was:
var testSet = new Set();
var testArray = [];
testSet.add("1");
testSet.add("2");
testSet.add("2"); // duplicate item
testSet.add("3");
var someFunction = function (value1, value2, setItself) {
testArray.push(value1);
};
testSet.forEach(someFunction);
console.log("testArray: " + testArray);
value1 equals value2 => The value contained in the the current position in the Set. The same value is passed for both arguments
Worked under IE11.
Using Set and converting it to an array is very similar to copying an Array...
So you can use the same methods for copying an array which is very easy in ES6
For example, you can use ...
Imagine you have this Set below:
const a = new Set(["Alireza", "Dezfoolian", "is", "a", "developer"]);
You can simply convert it using:
const b = [...a];
and the result is:
["Alireza", "Dezfoolian", "is", "a", "developer"]
An array and now you can use all methods that you can use for an array...
Other common ways of doing it:
const b = Array.from(a);
or using loops like:
const b = [];
a.forEach(v => b.push(v));
the simplistic way to doing this
const array = [...new Set([1,1,2,3,3,4,5])]
console.log(array)
Here is an easy way to get only unique raw values from array. If you convert the array to Set and after this, do the conversion from Set to array. This conversion works only for raw values, for objects in the array it is not valid. Try it by yourself.
let myObj1 = {
name: "Dany",
age: 35,
address: "str. My street N5"
}
let myObj2 = {
name: "Dany",
age: 35,
address: "str. My street N5"
}
var myArray = [55, 44, 65, myObj1, 44, myObj2, 15, 25, 65, 30];
console.log(myArray);
var mySet = new Set(myArray);
console.log(mySet);
console.log(mySet.size === myArray.length);// !! The size differs because Set has only unique items
let uniqueArray = [...mySet];
console.log(uniqueArray);
// Here you will see your new array have only unique elements with raw
// values. The objects are not filtered as unique values by Set.
// Try it by yourself.
I would prefer to start with removing duplications from an array and then try to sort.
Return the 1st element from new array.
function processData(myArray) {
var s = new Set(myArray);
var arr = [...s];
return arr.sort((a,b) => b-a)[1];
}
console.log(processData([2,3,6,6,5]);
function countUniqueValues(arr) {
return Array.from(new Set(arr)).length
}
console.log(countUniqueValues([1, 2, 3, 4, 4, 4, 7, 7, 12, 12, 13]))