How to replace duplicate objects from array - javascript

I know there are multiple ways to remove duplicates from arrays in javascript, the one i use is
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4]
let uniqueArray = array => [...new Set(array)]
console.log(uniqueArray) -> [1, 2, 3, 4]
what i want is something similar but instead of removing the duplicates, to replace it with whatever string or number i want, like this
console.log(uniqueArray) -> [1, 2, 3, 4, "-", "-", "-", "-"]
this has to work with any order, like
[1, 2, 3, 3, 4, 5, 7, 1, 6]
result -> [1, 2, 3, "-", 4, 5, 7, "-", 6]
i tested this solution
const arr = [1, 2, 3, 1, 2, 3, 2, 2, 3, 4, 5, 5, 12, 1, 23, 4, 1];
const deleteAndInsert = uniqueList => {
const creds = uniqueList.reduce((acc, val, ind, array) => {
let { count, res } = acc;
if (array.lastIndexOf(val) === ind) {
res.push(val);
} else {
count++;
};
return { res, count };
}, { count: 0, res: [] });
const { res, count } = creds;
return res.concat(" ".repeat(count).split(" "));
};
console.log(deleteAndInsert(arr));
but only adds it at the end of the uniques, and also, only works with numbers
i want it to work with strings too, like dates as an example
["2021-02-22", "2021-02-23", "2021-02-22", "2021-02-28"]

You could still use a Set and check if the value is in the set.
const
unique = array => array.map((s => v => !s.has(v) && s.add(v) ? v : '-')(new Set));
console.log(...unique([1, 2, 3, 4, 1, 2, 3, 4]));
console.log(...unique([1, 2, 3, 3, 4, 5, 7, 1, 6]));

Just create new Array, use 1 set to control which element appeared, if one element appears more than 1, push new one character like '-'
let originalArray = [1, 2, 3, 4, 1, 2, 3, 4];
let newArray = [];
let set = new Set();
for (let i = 0; i < originalArray.length; i++) {
if(!set.has(originalArray[i])) {
newArray.push(originalArray[i]);
set.add(originalArray[i]);
} else {
newArray.push('-');
}
}
console.log(newArray);

You could do it with reduce
const dashDupes = array => array.reduce((acc, e) => {
if(acc.idx[e])
acc.arr.push('-')
else{
acc.arr.push(e);
}
acc.idx[e] = true;
return acc;
},{idx:{},arr:[]}).arr
console.log(...dashDupes([1, 2, 3, 4, 1, 2, 3, 4]))
console.log(...dashDupes([1, 2, 3, 3, 4, 5, 7, 1, 6]))

This is a very simple approach to the problem:
function uniqueReplace(arr, rep) {
let res = [];
for (x of arr) {
res.push(res.includes(x) ? rep : x);
}
return res;
}
console.log(...uniqueReplace([1, 2, 3, 4, 1, 2, 3, 4], '-'));
console.log(...uniqueReplace([1, 2, 3, 3, 4, 5, 7, 1, 6], '-'));

Related

trying to create an array that prints out: how many there is of each value in an ARRAY

info before: i have halfway succeded, as i managed to print out it and it didnt loop crazy, however i did not manage to find the reason why it still prints out a undefinded
HTML: <button id="btn">button</button>
<label id="textarea"></label>
var tall = [4, 5, 2, 3, 4, 6, 1, 2, 0, 9, 7, 6, 8, 5, 6, 4, 2, 3, 5]
var btn = document.getElementById("btn");
tall.sort(function(a, b){return a-b})
btn.onclick = function(){
for( var i = 0; i < tall.length; i++){
a = 0;
for(var j = 0; j<i ; j++){
a++;
tall.splice(i, 2)
document.write("number "+tall[i]+" is "+ a+" times<br>")
}
}
}
we can use reduce to calculate how many times number is shown
then we can use Object.entries with forEach - to show data to UI
var tall = [4, 5, 2, 3, 4, 6, 1, 2, 0, 9, 7, 6, 8, 5, 6, 4, 2, 3, 5]
var btn = document.getElementById("btn");
btn.onclick = function(){
const objectResult = tall.reduce((a,c) => (a.hasOwnProperty(c) ? {...a, [c]: a[c] + 1} : {...a, [c]: 1}), {});
Object.entries(objectResult).forEach(([number, times]) => document.write(`number: ${number} is ${times} times<br>`))
}
<button id="btn">button</button>
<label id="textarea"></label>
Using the reduce function, you can iterate over your array and generate an output based on action you perform on each next Value in the Array.
We start with an empty object, if we find that the nextValue is not yet stored we store it in that object with value 1, if we see that the nextValue already exists, we increment the count in the result.
const data = [4, 5, 2, 3, 4, 6, 1, 2, 0, 9, 7, 6, 8, 5, 6, 4, 2, 3, 5]
const result = data.reduce((result, nextValue) => {
if (nextValue in result)
result[nextValue]++
else
result[nextValue] = 1
return result
}, {}) // initial result is an empty object set with ', {}'
console.log(result)
var tall = [4, 5, 2, 3, 4, 6, 1, 2, 0, 9, 7, 6, 8, 5, 6, 4, 2, 3, 5];
var map = tall.reduce(function(prev, cur) {
prev[cur] = (prev[cur] || 0) + 1;
return prev;
}, {});
console.log(map)
Here you go:
const list = document.querySelector('ul')
const button = document.querySelector('button')
const tall = [4, 5, 2, 3, 4, 6, 1, 2, 0, 9, 7, 6, 8, 5, 6, 4, 2, 3, 5]
// Cals result
const result = tall.reduce((res, value) => {
if (value in res)
res[value]++
else
res[value] = 1
return res
}, {})
button.addEventListener('click', () => {
list.innerHTML = ''
// Add li element for each result
Object.keys(result).forEach(res => {
const li = document.createElement('li')
li.textContent = `${res} occures ${result[res]} times`
list.append(li)
})
})
<button>Write data to list</button>
<ul>
<ul>
This will give you the occurrences of each number in an object.

Check to see if an array contains all elements of another array, including whether duplicates appear twice

I need to check whether one array contains all of the elements of another array, including the same duplicates. The second array can have extra elements. I'm using every...includes, but it's not catching that the second array doesn't have the right duplicates.
For example:
const arr1 = [1, 2, 2, 3, 5, 5, 6, 6]
const arr2 = [1, 2, 3, 5, 6, 7]
if(arr1.every(elem => arr2.includes(elem))){
return true // should return false because arr2 does not have the same duplicates
}
Thanks!
Edit: arr1 is one of many arrays that I am looping through which are coming out of a graph traversal algorithm, so I'd like to avoid restructuring them into an object to create a dictionary data structure if possible.
Try creating this function:
function containsAll (target, toTest) {
const dictionary = {}
target.forEach(element => {
if (dictionary[element] === undefined) {
dictionary[element] = 1;
return;
}
dictionary[element]++;
});
toTest.forEach(element => {
if (dictionary[element] !== undefined)
dictionary[element]--;
})
for (let key in dictionary) {
if (dictionary[key] > 0) return false;
}
return true;
}
Then invoke it like this:
const arr1 = [1, 2, 2, 3, 5, 5, 6, 6]
const arr2 = [1, 2, 3, 5, 6, 7]
console.log(containsAll(arr1, arr2)) // returns false
const arr1 = [1, 2, 2, 3, 5, 5, 6, 6];
//const arr2 = [1, 2, 3, 5, 6, 7];
const arr2 = [1, 2, 2, 3, 5, 5];
let includesAll1 = true;
let includesAll2 = true;
const checkObj1 = {
};
const checkObj2 = {
};
arr1.forEach((el)=> {
if(checkObj1[el] === undefined) {
checkObj1[el] = 1;
} else {
checkObj1[el]++;
}
});
arr2.forEach((el)=> {
if(checkObj2[el] === undefined) {
checkObj2[el] = 1;
} else {
checkObj2[el]++;
}
});
const check1Keys = Object.keys(checkObj1);
const check2Keys = Object.keys(checkObj2);
if(check1Keys.length > check2Keys.length) {
includesAll2 = false;
check2Keys.forEach((key)=> {
const value1 = checkObj1[key];
const value2 = checkObj2[key];
if(!arr1.includes(parseInt(key)) || value1 != value2) {
includesAll1 = false;
}
});
} else {
includesAll1 = false;
check1Keys.forEach((key)=> {
const value1 = checkObj1[key];
const value2 = checkObj2[key];
console.log(value1, value2, key);
if(!arr2.includes(parseInt(key)) || value1 != value2) {
includesAll2 = false;
}
});
}
console.log(includesAll1);
console.log(includesAll2);
Does this solve your problem?
const arr = [1, 2, 3, 5, 6, 7, 2, 10, 2, 3, 2];
const subArr = [1, 2, 2, 3, 2]
const contains = subArr.every(num => subArr.filter(n => n == num).length <= arr.filter(n => n== num).length);
console.log(contains);
You indicate order does not matter in your comments. That makes this very simple.
Sort both arrays
Check if corresponding elements are equal
consider errors associated with sparse or short arrays
Use .reduce() to boil it down to a single result
So this really comes down to a single statement once the arrays are sorted:
matcher.reduce((acc, value , idx)=>matcher[idx] === test[idx], false);
You also mentioned testing this against many arrays. So the full example below does that for demo purposes.
let toMatch = [1, 2, 2, 3, 5, 5, 6, 6]
let arrayOfArrays = [[1,2],[1, 2, 3, 5, 6, 7, 3, 9, 8, 2, 7],[1, 2, 3, 3, 6, 7],[1, 3, 3, 5, 6, 7],[1, 2, 3, 5, 6, 6], [3,5,2,1,6,2,5,6]];
let toMatchSorted = toMatch.slice().sort();
arrayOfArrays.forEach(arr=>{
let toTestSorted = arr.slice().sort();
let out = toMatchSorted.reduce((acc, value , idx)=>toMatchSorted[idx] === toTestSorted[idx], false);
console.log(`Input: ${arr}, Result: ${out}`);
});

Remove all of the duplicate numbers in an array of numbers [duplicate]

This question already has answers here:
Get all unique values in a JavaScript array (remove duplicates)
(91 answers)
Closed 3 years ago.
I received this question for practice and the wording confused me, as I see 2 results that it might want.
And either way, I'd like to see both solutions.
For example, if I have an array:
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
I'm taking this as wanting the final result as either:
let finalResult = [1, 2, 3, 4, 5, 8, 9, 10];
OR:
let finalResult = [1, 9, 10];
The difference between the two being, one just removes any duplicate numbers and leaves the rest and the second just wants any number that isn't a duplicate.
Either way, I'd like to write two functions that does one of each.
This, given by someone else gives my second solution.
let elems = {},
arr2 = arr.filter(function (e) {
if (elems[e] === undefined) {
elems[e] = true;
return true;
}
return false;
});
console.log(arr2);
I'm not sure about a function for the first one (remove all duplicates).
Using Set and Array.from()
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
console.log(Array.from(new Set(arr)));
Alternate using regex
regex explanation here
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let res = arr
.join(',')
.replace(/(\b,\w+\b)(?=.*\1)/ig, '')
.split(',')
.map(Number);
console.log(res);
Alternate using objects
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let obj = arr.reduce((acc, val) => Object.assign(acc, {
[val]: val
}), {});
console.log(Object.values(obj));
Just use a simple array.filter one-liner:
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let finalResult = arr.filter((e, i, a) => a.indexOf(e) == i).sort(function(a, b){return a - b});
console.log(finalResult);
You could use another filter statement if you wanted the second result:
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let finalResult = arr.filter((e, i, a) => a.filter(f => f == e).length == 1).sort(function(a, b){return a - b});
console.log(finalResult);
For the first part you can use Set() and Spread Syntax to remove duplicates.
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let res = [...new Set(arr)]
console.log(res)
For the second part you can use reduce()
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
//to get the object with count of each number in array.
let obj = arr.reduce((ac,a) => {
//check if number doesnot occur before then set its count to 1
if(!ac[a]) ac[a] = 1;
//if number is already in object increase its count
else ac[a]++;
return ac;
},{})
//Using reduce on all the keys of object means all numbers.
let res = Object.keys(obj).reduce((ac,a) => {
//check if count of current number 'a' is `1` in the above object then add it into array
if(obj[a] === 1) ac.push(+a)
return ac;
},[])
console.log(res)
You can use closure and Map
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
const build = ar => {
const mapObj = ar.reduce((acc, e) => {
acc.has(e) ? acc.set(e, true) : acc.set(e, false)
return acc
}, new Map())
return function(hasDup = true) {
if(hasDup) return [...mapObj.keys()]
else return [...mapObj].filter(([key, val]) => !val).map(([k, v])=> k)
}
}
const getArr = build(arr)
console.log(getArr())
console.log(getArr(false))
You can create both arrays in One Go
let arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
let unique = new Set();
let repeated = Array.from(arr.reduce((acc, curr) => {
acc.has(curr) ? unique.delete(curr) : acc.add(curr) && unique.add(curr);
return acc;
}, new Set()));
console.log(Array.from(unique))
console.log(repeated)
You can use Array.prototype.reduce() create a hash object where the keys are the numbers in the array and the values are going to be the the repeated occurrence of numbers in the arr array variable..
Then using Object.keys():
Remove all duplicates Object.keys(hash)
Remove all duplicates but filtering with Array.prototype.filter() to get the numbers with only one occurrence
Code:
const arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
const hash = arr.reduce((a, c) => (a[c] = (a[c] || 0) + 1, a), {});
// [1, 2, 3, 4, 5, 8, 9, 10];
const finalResultOne = Object.keys(hash);
// [1, 9, 10];
const finalResultTwo = Object.keys(hash).filter(k => hash[k] === 1);
console.log('finalResultOne:', ...finalResultOne);
console.log('finalResultTwo:', ...finalResultTwo);
You could sort the array before and filter the array by checking only one side for duplicates or both sides.
var array = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10],
result1,
result2;
array.sort((a, b) => a - b);
result1 = array.filter((v, i, a) => a[i - 1] !== v);
result2 = array.filter((v, i, a) => a[i - 1] !== v && a[i + 1] !== v);
console.log(...result1);
console.log(...result2)
As many other have said, the first one is just [...new Set(arr)]
For the second, just filter out those that occur more than once:
const arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
const count = (arr, e) => arr.filter(n => n == e).length
const unique = arr => arr.filter(e => count(arr, e) < 2)
console.log(unique(arr));
var arr = [1, 2, 4, 2, 3, 3, 4, 5, 5, 5, 8, 8, 9, 10];
var map = {};
var finalResult = [];
for (var i = 0; i < arr.length; i++) {
if (!map.hasOwnProperty(arr[i])) {
map[arr[i]] = true;
finalResult.push(arr[i]);
}
}
//if you need it sorted otherwise it will be in order
finalResult.sort(function(a, b) {
return a - b
});
console.log(finalResult);

Sort array of numbers by normal distribution (gaussian distribution)

Having an array of numbers setOfNumbers = [0, 3, 3, 2, 7, 1, -2, 9] I'd like to sort this set to have the smallest numbers on the end and beginning and the biggest in the center of the sorted set like this sortedSetNumbers = [0, 2, 3, 9, 7, 3, 1, -2].
const setOfNumbers = [0, 3, 3, 2, 7, 1, -2, 9];
const result = [0, 2, 3, 9, 7, 3, 1, -2];
function sortNormal(a, b) {
return true; // Please, change this line
}
const sortedSetNumbers = setOfNumbers.sort((a, b) => sortNormal(a, b));
if (sortedSetNumbers === result) {
console.info('Succeeded Normal Distributed');
} else {
console.warn('Failed Normal Distribution');
}
console.log(sortedSetNumbers);
I am sure it is possible to sort these numbers with the method Array.prototype.sort(), but how should this sorting function look like?
EDIT: The solution does not have to be solved with .sort(). That was only an idea.
This might be the most naive way to do it, but isn't it simply left, right, left, right... after sorting?
const input = [0, 3, 3, 2, 7, 1, -2, 9];
const expected = [0, 2, 3, 9, 7, 3, 1, -2];
const sorted = input.slice().sort();
const output = [];
let side = true;
while (sorted.length) {
output[side ? 'unshift' : 'push'](sorted.pop());
side = !side;
}
console.log(expected.join());
console.log(output.join());
Or simply:
const input = [0, 3, 3, 2, 7, 1, -2, 9];
const output = input.slice().sort().reduceRight((acc, val, i) => {
return i % 2 === 0 ? [...acc, val] : [val, ...acc];
}, []);
console.log(output.join());
A slightly different approach is to sort the array ascending.
Get another array of the indices and sort the odds into the first half asending and the even values to the end descending with a inverted butterfly shuffle.
Then map the sorted array by taking the value of the sorted indices.
[-2, 0, 1, 2, 3, 3, 7, 9] // sorted array
[ 1, 3, 5, 7, 6, 4, 2, 0] // sorted indices
[ 0, 2, 3, 9, 7, 3, 1, -2] // rebuild sorted array
var array = [0, 3, 3, 2, 7, 1, -2, 9].sort((a, b) => a - b);
array = Array
.from(array, (_, i) => i)
.sort((a, b) => b % 2 - a % 2 || (a % 2 ? a - b : b - a))
.map(i => array[i]);
console.log(array);
This solution is not really elegant, but it does it's job.
const setOfNumbers = [0, 3, 3, 2, 7, 1, -2, 9];
const alternation = alternate();
const sortedSetNumbers = sortNormal(setOfNumbers);
function sortNormal(start) {
const result = [];
const interim = start.sort((a, b) => {
return b - a;
});
interim.map(n => {
if (alternation.next().value) {
result.splice(0, 0, n);
} else {
result.splice(result.length, 0, n);
}
});
return result;
}
function* alternate() {
let i = true;
while (true) {
yield i;
i = !i;
}
}
console.log(sortedSetNumbers);

Removing duplicates in an ordered array

What I'm trying to do is find how many times an array elements repeats itself in array, push the element along with the number of repeats it has in an object and after that delete the element and all its duplicates.
At the moment I have this function :
function getDuplicates(arr) {
let lastIndex = null;
let obj = {};
for ( let i = 0; i < arr.length; i++ ) {
lastIndex = arr.lastIndexOf(arr[i]);
obj[arr[i]] = lastIndex + 1;
arr.splice(0, lastIndex + 1 );
}
console.log(obj);
}
getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
which logs : { '1': 4, '2': 2, '3': 4, '5': 5 }
It works great for the first 3 numbers ( 1,2 and 3 ) but 4 doesnt show up, 5 is messed up and 6 doesnt show due to lastIndex +1. Am I missing something or is there a better way to do this ?
Thank you.
You can simplify a lot the logic. Just an object to count and an if statement to increment values or define as 1 if it wasn't defined.
function countDuplicates(arr) {
// Contains a pair of values an instances.
var counting = {};
// Iterate array: check if already counted. If yes, increment, if not define as 1.
for (el of arr) (counting[el]) ? counting[el]++ : counting[el] = 1;
console.log(counting);
return counting;
}
countDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
Adding, if you also want to get the unique elements, you can just use E6 set:
var set = new Set([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
You can count and print as you would want like this:
function getDuplicates(arr) {
var counts = {};
arr.forEach(function(x) { counts[x] = (counts[x] || 0)+1; });
console.log(counts);
}
function getDuplicates(arr) {
let lastNum = null;
let obj = {};
for ( let i = 0; i < arr.length; i++ ) {
if (arr[i] != lastNum){
lastNum = arr[i];
obj[arr[i]] = 1;
}else{
obj[arr[i]]++;
}
}
console.log(obj);
}
You can simply use Array#reduce() to count the occurrences and Array#filter() to remove the duplicates
getDuplicates([1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6]);
function getDuplicates(arr) {
var obj = arr.reduce((map, item) => (map[item] = ++map[item] || 1, map),{} );
var withoutDup = arr.filter((item, pos) => arr.indexOf(item) == pos);
console.log(JSON.stringify(obj));
console.log(JSON.stringify(withoutDup));
}
Here's one method how to solve it.
Firstly I've removed all duplicated elements from the given array, using new Set() and then iterated over it using Array#forEach and checked with Array#filter how many times given element appears in the passed array.
function getDuplicates(arr){
var filtered = [...new Set(arr)],
result = {};
filtered.forEach(function(v){
result[v] = arr.filter(c => c == v).length;
})
console.log(result);
}
getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]);
Array#reduce solution.
function getDuplicates(arr) {
var res = arr.reduce(function(s, a) {
s[a] = arr.filter(c => c == a).length;
return s;
}, {});
console.log(res);
}
getDuplicates([1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6]);
It looks as if you want to COUNT duplicates, but if all you want to do is remove duplicates (As headline states), as per #ChantryCargill s suggestion:
function removeDuplicates (arr) {
var results = [];
for(var i = 0; i < arr.length; i++) {
var item = arr[i];
if(results.indexOf(item) === -1) {
results.push(item);
}
}
return results;
}
console.log(removeDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]));
//[1, 2, 3, 4, 5, 6]
If you want to COUNT duplicates:
function getDuplicates(arr) {
var results = {};
for(var item of arr) {
if(!results[item]) {
results[item] = 0;
}
results[item]++;
}
return results;
}
console.log(getDuplicates([ 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 6 ]));
//{"1":4,"2":2,"3":4,"4":2,"5":3,"6":1}
Try this:
function getDuplicates(){
var numbers=Array.prototype.slice.call(arguments);
var duplicates={};
for(var index in numbers){
if(numbers.indexOf(numbers[index])==index)
continue;
duplicates[numbers[index]]= (duplicates[numbers[index]] || 0) + 1;
}
return duplicates;
}
console.log(getDuplicates(1,2,3,1,1,3,4,5,6,7,8,6));
/*
prints {
1: 2,
3: 1,
6: 1
}
*/

Categories

Resources