Removing Duplicates in Arrays - javascript

I am trying to pass a function that removes duplicates from an array. It should handle strings, object, integers as well. In my code so far I am showing that it will handle strings but nothing else. How can Imake this function universalto handle numbers,handle arrays,handle objects, and mixed types?
let unique = (a) => a.filter((el, i ,self) => self.indexOf(el) ===i);
In this function I hav unique() filtering to make a new array which checks the element and index in the array to check if duplicate. Any help would be appreciated.

i think the first you should do is to sort the array ( input to the function ). Sorting it makes all the array element to be ordered properly. for example if you have in an array [ 1, 3, 4, 'a', 'c', 'a'], sorting this will result to [ 1 , 3 , 4, 'a', 'a' , 'c' ], the next thing is to filter the returned array.
const unique = a => {
if ( ! Array.isArray(a) )
throw new Error(`${a} is not an array`);
let val = a.sort().filter( (value, idx, array) =>
array[++idx] != value
)
return val;
}
let array = [ 1 , 5, 3, 2, "d", "q", "b" , "d" ];
unique(array); // [1, 2, 3, 5, "b", "d", "q"]
let obj = { foo: "bar" };
let arraySize = array.length;
array[arraySize] = obj;
array[arraySize++] = "foo";
array[arraySize++] = "baz";
array[arraySize++] = obj;
unique(array); // [1, 2, 3, 5, {…}, "b", "baz", "d", "foo", "hi", "q"]
it also works for all types, but if you pass in an array literal with arrays or objects as one of its element this code will fail
unique( [ "a", 1 , 3 , "a", 3 , 3, { foo: "baz" }, { foo: "baz" } ] ); // it will not remove the duplicate of { foo: "baz" } , because they both have a different memory address
and you should also note that this code does not return the array in the same order it was passed in , this is as a result of the sort array method

Try using sets without generics. You can write a function as
Set returnUnique(Object array[]) {
Set set=new HashSet();
for (Object obj:array) {
set.add(obj);
}
return set;
}

Related

How can I filter an array containing varied object structures dynamically?

My usage will contain 6 different object types (some which contain double nested arrays), and any possibility of number of entries, on the condition that an given entry is unique.
These objects do not have a consistent unique identifier (a unique identifier is applied in backend on submission).
here is an example of what the array may look like (only 2 object types):
arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{timeline: "250", chars[{a},{b},{c}]},
{timeline: "220", chars[{d},{e},{f}]},
]
obj = {name:"aaa",time:22}
My intention is to gain a true or false based on if obj is inside arr
I have tried methods:
I was suggested this method & it errors: #<Object> is not a function
console.log(arr.find(obj))
I also found this suggestion but it will always return false even with the element present
console.log(arr.includes(object))
I tried this method myself, though it will always fail.
console.log(arr.filter((element, index) => element === obj)
With attempt 4, If I was to compare name, this would be insufficient as unique time would be ignored missing valid entries.
If I was to pass every field, this would also not work as each object may or may not have the field and cause error.
Its not really possible to manually pre-filter filter into distinct categories, as every time a new type is added it will need manually adding to the filter.
If there is a library which could do this that you know of, please let me know as that would be perfect. Otherwise any other suggestions (excluding separating arrays) Would be greatly appreciated.
Use arr.some() to check if the required object is present in the array.
To compare the objects, a simpler way is to Stringify both the Objects and compare them.
const arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{name: "aaa", chars: ["a", "b", "c"]},
{name: "bbb", chars: ["d", "e", "f"]},
]
const obj1 = {name:"aaa", time: 15}
const obj2 = {name:"aaa",chars: ["a", "b", "c"]}
console.log(arr.some((element) => JSON.stringify(element) === JSON.stringify(obj1))) // true
console.log(arr.some((element) => JSON.stringify(element) === JSON.stringify(obj2))) // true
Didn't give much thought on performance.
I didn't put much thought on performace here but this might help:
function checkObjectInArray(arr, obj) {
const res = arr.some((el) => deepEqual(el, obj));
console.log(res);
}
function deepEqual(obj1, obj2) {
if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;
for (let prop in obj1) {
if (!obj2.hasOwnProperty(prop) || obj2[prop] !== obj1[prop]) {
return false;
}
}
return true;
}
in your case you can use it like:
arr = [
{ name: "aaa", time: 15 },
{ name: "aaa", time: 22 },
{ timeline: "250", data: ["2", "3", "4"] },
{ timeline: "251", data: ["2", "3", "4"] }, // what is chars[{d},{e},{f}] ?!
];
obj = { name: "aaa", time: 22 };
checkObjectInArray(arr, obj);
Observation : arr is not a valid array. Nested chars is not containing a valid value.
Solution : You can simply achieve the requirement by Just converting the JSON object into a JSON string and by comparing.
This solution works fine as you are just trying to find a single object in the passed arr.
Live Demo :
const arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{timeline: "250", chars: [{a: 1},{b: 2},{c: 3}]},
{timeline: "220", chars: [{d: 4},{e: 5},{f: 6}]},
];
const obj = {name:"aaa",time:22};
const res = JSON.stringify(arr).indexOf(JSON.stringify(obj)) !== -1 ? true : false;
console.log(res);

javascript equivalent to [x for x in array]

Is there any operation in Javascript just like [x for x in array] in python?
For example, I'm using javascript to reading a json file where there're dozens of (key, value) pairs needed to be handled(or transformed into other format). And I thought working in this way is stupid:
let transformed = []
for (let key in json){
transformed = [ /* doing some transform*/ ]
}
Is there anything like:
let transformed = [
lambda function1(key), lambda function2(value) for key, value in json
]
Thanks in advance.
The rough equivalent of Python's list comprehension is Array.map:
const myArray = [1, 2, 3]
const transformed = myArray.map((item) => item + 1)
// [2, 3, 4]
But your example is not about an array, but about an Object with keys and values. In Python, this would be a dict, and you'd use a dict comprehension along the lines of {function1(key): function2(value) for key, value in my_dict.items()}.
In JavaScript, you can turn such an object into an array with Object.entries, then perform the map, and finally transform it back into an object using Object.fromEntries:
const myObject = { a: 1, b: 2 }
const transformed = Object.fromEntries(Object.entries(myObject)
.map(([key, value]) => [key + 'x', value + 1]))
// { ax: 2, bx: 3 }
Note that fromEntries is fairly new and you might need to add a polyfill for it.
You can use a code likes this. You must use a function that handle operation on current single item.
const words = ['hello', 'bird', 'table', 'football', 'pipe', 'code'];
const capWords = words.forEach(capitalize);
function capitalize(word, index, arr) {
arr[index] = word[0].toUpperCase() + word.substring(1);
}
console.log(words);
// Expected output:
// ["Hello", "Bird", "Table", "Football", "Pipe", "Code"]
First of all, javascript does NOT support Associative Arrays. If you are used to them in Python, PHP, and other languages you need to do a little workaround in JS to achieve the same functionality.
The most common way to simulate an associative array is using an object.
let testObject = {name: "Color", value: "Red"};
And then you push every object into an array so you end up with something like this:
let testArray = [{name: "Color", value: "Red"}, {name: "Color", value: "Blue"}];
Once you have this array consisting of objects, you can use map function to go through every object in the array and do whatever you want with it.
testArray.map((item, index) => {
console.log("The value of "+index+". item is: "item.value);
})
You can use Array.map() function. It work pretty like Array.forEach() function
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map((element) => {
return element * 2
})
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
It can be reduce using
const numbers = [1, 2, 3, 4, 5]
let newArray = numbers.map(element => element * 2)
console.log(newArray) // excepted : [ 2, 4, 6, 8, 10 ]
For more informations, you can this documentation https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/map

JavaScript: Find in array all values with substrings of array

I have two arrays; one with substrings and the other with objects.
I would like to obtain an array of objects where those objects contain any of the substrings in the substrings array.
So far I have tried to use filter and findIndex. Each approach works if a substring is identical. In this case, even indexOf was not working. I am not javascript guy, so probably I am doing something wrong.
Script
var strings = ['12', 'sv', 'eli', '23', '34'];
var data = [
{
a: 349531284734,
b: "sv123eippppppeli",
c: "aaabbbccc"
},
{
a: 1111123333312,
b: "ccccccccccccs2222",
c: "aaabbbccc"
},
{
a: 2222234,
b: "elllllllla",
c: false
},
];
// attempt 1
var results = data.filter(arr =>
Object.keys(arr).some(key => {
return String(arr[key]).toLowerCase().includes(strings) // or indexOf
})
);
// attempt 2 with only one data index
var obj = Object.values(data[0]);
var results = strings.some(s => obj.includes(s)) // or indexOf or findIndex;
Explanation
In this example with the given substrings, only data[0] is a match because it contains at least on of the substrings in the strings array.
How can I make this work without using a "for loop"?
Thanks
A simple solution that avoids the need for "for-loop" syntax would be to filter() each object of data by a predicate that checks if any value (of the current item being filtered) contains any one of the values of the strings array.
In code, this can be expressed as:
var strings = ['12', 'sv', 'eli', '23', '34'];
var data = [{
a: 349531284734,
b: "sv123eippppppeli",
c: "aaabbbccc"
},
{
a: 1111123333312,
b: "ccccccccccccs2222",
c: "aaabbbccc"
},
{
a: 2222234,
b: "elllllllla",
c: false
},
];
// Local helper retruns true if case-insenstive value in strings array
const stringHasValue = (value) => strings
.some(str => value.toLowerCase().includes(str.toLowerCase()))
// Filter each item in data array by existance of a value containing
// substring in strings array
var result = data.filter((item) => Object.values(item)
.filter(value => typeof value === 'string')
.some(stringHasValue, []));
console.log(result);

Just for kicks: Creating/deep-copying multidimensional arrays in JavaScript and accounting for variable length?

I volunteer teaching coding to young girls to code and one of the more advanced ones was trying to use a 2D array for her JavaScript project, but was struggling with the concept of multidimensional arrays. I started putting together a tutorial on arrays and multidimensional arrays to review with her next week, got a little carried away with writing a matrix searching demo, and then realized I don't know a great way of deep copying or creating filled multidimensional arrays that copy the potentially variable-length dimensions of another array (e.g., for storing visited cell data when searching) in JavaScript, which I've only really learned/used within the last year-ish. This is what I came up with:
/**
* #param mdArray A multidimensional array that may contain variable length arrays
* #param fillValue The value to fill the cells with
*
* #return A multidimensional array with the same dimensions as mdArray where
* each cell is filled with fillValue
*/
function createFilledMultidimensionalArray(mdArray, fillValue) {
// Create a new array with mdArray.length rows
return new Array(mdArray.length).fill().map( function (elt, row) {
// Populate each row with a new filled array containing fillValue
return new Array(mdArray[row].length).fill(fillValue);
}
);
}
/**
* #param mdArray A multidimensional array that may contain variable length arrays
*
* #return A deep copy of mdArray
*/
function multidimensionalArrayCopy(mdArray) {
return JSON.parse(JSON.stringify(mdArray));
// note: I'm aware this isn't a universally perfect deep copy *shrug*
}
/* Testing */
// Create a ridiculous array containing variable-length arrays
var multidimensionalArray = [[6, { a: '1', b: 2 }], [1, 2], [3, 4, 5], ['seven']];
// Copy and print the array
var copied = multidimensionalArrayCopy(multidimensionalArray);
console.log(multidimensionalArray);
// Prints: [ [ 6, { a: '1', b: 2 } ], [ 1, 2 ], [ 3, 4, 5 ], [ 'seven' ] ]
// Modify a value
multidimensionalArray[0][1].b = 'hi';
// Print both arrays, observe copy is deep
console.log(multidimensionalArray);
console.log(copied);
/* Prints:
[ [ 6, { a: '1', b: 'hi' } ], [ 1, 2 ], [ 3, 4, 5 ], [ 'seven' ] ]
[ [ 6, { a: '1', b: 2 } ], [ 1, 2 ], [ 3, 4, 5 ], [ 'seven' ] ]
*/
// Create a new array with same dimensions as 'copied' where each cell is filled with 'false'
console.log(createFilledMultidimensionalArray(copied, false));
/* Prints:
[ [ false, false ],
[ false, false ],
[ false, false, false ],
[ false ] ]
*/
Does anyone else out there with more JS experience have any other ideas? (Please don't suggest slice, which shallow copies.)
You could use a recursive clone function instead of stringifying your data. Then for filling multi-dimension arrays, you could use a recursive deepMap function that calls itself on nested arrays:
function clone(value) {
if(Array.isArray(value)) return value.map(clone);
if(typeof value === 'object') {
return Object.entries(value).reduce((cloned, [key, value]) => {
cloned[key] = clone(value);
return cloned;
}, {});
}
return value;
}
function deepMap(array, fn) {
return array.map(value =>
Array.isArray(value)
? deepMap(value, fn)
: fn(value)
);
}
function deepFill(array, fillValue) {
return deepMap(array, () => fillValue);
}
const original = [
[1, 2, 3],
[{value: 'unchanged'}, 5, 6],
[false, true],
[7, 8, [9, 10], 11, 12],
];
const cloned = clone(original);
const filled = deepFill(original, 'fill');
cloned[1][0].value = 'changed';
console.log(
original[1][0].value,
cloned[1][0].value,
);
console.log(filled);

How do object references work internally in javascript

I am very new to javascript.
I have written the simple code:
var temp = {}
var arr = []
temp['a'] = ['a']
arr.push(temp)
console.log(arr);
As expected, it prints:
[ { a: [ 'a' ] } ]
But then, when I append the following line to the previous code:
temp['b'] = ['b']
arr.push(temp);
console.log(arr);
I would have expected it to print:
[ { a: [ 'a' ] }, { a: [ 'a' ], b: [ 'b' ] } ]
But it prints:
[ { a: [ 'a' ], b: [ 'b' ] }, { a: [ 'a' ], b: [ 'b' ] } ]
Entire code for unexpected result:
var temp = {}
var arr = []
temp['a'] = ['a']
arr.push(temp)
console.log(arr);
temp['b'] = ['b']
arr.push(temp);
console.log(arr);
Why did the first element of array got updated?
The following code gave me expected result:
var temp = {}
var arr = []
temp['a'] = ['a']
arr.push(temp)
console.log(arr);
temp = {};
temp['a'] = ['a']
temp['b'] = ['b']
arr.push(temp);
console.log(arr);
How does adding temp = {} helped here?
Objects in Javascript are passed by reference. That is, only one object is created and the symbol that represents that object can be used but it will refer to the same object always.
Lets take a deeper look:
If I'm understanding your example correct, this part
var temp = {}
var arr = []
temp['a'] = ['a']
arr.push(temp)
console.log(arr);
Creates a local variable temp to which you add ['a'] to. You then push that into arr.
So at this point, arr references the object temp and looks like this:
[ { a: [ 'a' ] } ]
When you do this:
temp['b'] = ['b']
arr.push(temp);
console.log(arr);
The temp symbol which points to the original object containing ['a'] is updated, and so the arr will also get updated, so arr contains this at that point:
[ { a: [ 'a' ], b: [ 'b' ] }, { a: [ 'a' ], b: [ 'b' ] } ]
Finally,
You then do this instead:
temp = {};
temp['a'] = ['a']
temp['b'] = ['b']
arr.push(temp);
console.log(arr);
This creates a separate global variable temp, onto which you add both
['a'] and ['b']. This is global because it does not have the var keyword in the declaration/initialization. This then gets pushed into the arr. However, since it's a global variable and not the original local variable, you see this instead:
[ { a: [ 'a' ] }, { a: [ 'a' ], b: [ 'b' ] } ]
In first case, arr[0] has temp's reference, arr[1] also has temp's reference. So, arr[0] and arr[1] have the same reference.
Hence updating the reference will update it everywhere where the reference is
being referred.
In second case however, when you do temp = {} you're just reassigning temp to a new reference, before pushing it. So, there's no relationship between the arr[0]'s reference, and hence updating temp now, only affects it.
The examples are not the same, it doesn't have to do with temp = {}.
In the first example you push temp twice, meaning arr has to references 2 temp.
After the first push you add another item to temp so within arr, if you had print it, you would have seen:
[ { a: [ 'a' ], b: [ 'b' ] } ]
So try this out on the console:
var temp = {}
var arr = []
temp['a'] = ['a']
arr.push(temp)
temp['b'] = ['b']
console.log(arr);
You'll see the result:
[ { a: [ 'a' ], b: [ 'b' ] } ]
Pushing another temp into arr is just going to result into two references into temp.
There are two data types in JavaScript - value types and reference types.
Value types are actually copied as they are sent between objects. This is because this is what you would expect for certain things like numbers and booleans.
Say I pass the number 1 to a function that stores it in an object A.
It would be surprising if I could then subsequently modify the value contained in A simply by modifying the value of the original number. Hence, pass by value. There are also optimizations that can be performed for value types.
Objects (i.e. everything other than number literals, boolean literals, null, undefined, and string literals*) are reference types in JavaScript and only their reference is passed around. This is largely for efficiency reasons. In your example, temp is an object. It is therefore passed by reference.
And so
temp['b'] = ['b']
Modifies the single existing instance of temp, thereby modifying the contents of arr, before you then also push temp into arr for a second time.
So you end up with an array containing two references to a single object temp, giving you the observed result.
* There is some complexity surrounding the string implementation that I am purposefully ignoring here.

Categories