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
}
*/
Related
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.
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}`);
});
So I have this code:
var myArray = [];
var value = 5;
while (myArray != [5, 4, 3, 2, 1, 0]) {
myArray.push(value)
value--;
console.log(myArray);
}
when I look at the console, it goes on for an infinite loop like so..
[ 5 ]
[ 5, 4 ]
[ 5, 4, 3 ]
[ 5, 4, 3, 2 ]
[ 5, 4, 3, 2, 1 ]
[ 5, 4, 3, 2, 1, 0 ]
[ 5, 4, 3, 2, 1, 0, -1 ]
[ 5, 4, 3, 2, 1, 0, -1, -2 ]
[ 5, 4, 3, 2, 1, 0, -1, -2, -3 ]
..........
Why doesn't it stop at [5,4,3,2,1,0] ? myArray = that at a point and the for loop should stop no?
Sorry for the noob question.
JavaScript does not provide built-in support for structural-equality of Arrays, but it's straightforward to implement a comparator:
function arraysEqual(a, b, orderSensitive = true) {
// Function from https://stackoverflow.com/a/16436975/159145
// But modified to add the `orderSensitive` option.
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length != b.length) return false;
if (!orderSensitive) {
a = Array.from(a).sort();
b = Array.from(b).sort();
}
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
function yourCode() {
var myArray = [];
var value = 5;
const finalArray = [5, 4, 3, 2, 1, 0];
while (!arraysEqual(myArray,finalArray)) {
myArray.push(value)
value--;
console.log(myArray);
}
}
you can use the following way to fix the issue if index and values of both arrays are different
while(sortArray(myArray).toString() !== sortArray([5, 4, 3, 2, 1, 0]).toString()) {
// your code
}
sortArray(array) {
return array.filter((a, b) => a-b)
}
If you are sure the array index and values for both arrays are same you can use
while(myArray.toString() !== [5, 4, 3, 2, 1, 0].toString()) {
// your code
}
#Christopher Barreto and welcome to StackOverflow. Good luck with your interesting question.
although #Dai right with his full answer there is much simpler built in a way to convert array to string and then compare them.
That will work for you:
var myArray = [];
var value = 5;
while (myArray.toString() != [5, 4, 3, 2, 1, 0].toString()) {
myArray.push(value)
value--;
console.log(myArray);
}
Or this if you prefer:
while ((''+myArray) != ('' + [5, 4, 3, 2, 1, 0]))
This question already has answers here:
How to remove repeated entries from an array while preserving non-consecutive duplicates?
(5 answers)
Closed 6 years ago.
I am trying to remove duplicates in an array in JavaScript. The given array being
array = [1,1,1,1,1,1,1,1,1,,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,1,1,1,1,1,2,2,2,2,2,2,2,2]
resultant_array = [1,2,3,1,2]
Here the second 1 is not considered as a duplicate
OR
array = [1,1,1,1,1,1,1,1,1,1,1,1]
resultant_array = [1]
any ideas how i can do this
You can use reduce like this:
var array = [1,1,1,1,1,1,1,1,1,,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,1,1,1,1,1,2,2,2,2,2,2,22];
var result = array.reduce(function(r, e) {
if(r[r.length - 1] != e) // if the last element in the result is not equal to this item, then push it (note: if r is empty then r[-1] will be undefined so the item will be pushed as any number is != undefined)
r.push(e);
return r;
}, []);
console.log(result);
var arr = [1,1,2,2,3,3];
var obj = {};
for(var i in arr) {
obj[arr[i]] = true;
}
var result = [];
for(var i in obj) {
result.push(i);
}
I set the keys of the object as the value of the array and there can't be multiple keys with the same value. Then I took all the keys and put it in the result.
You could check the predecessor with Array#reduce
var array = [1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2],
result = array.reduce(function (r, a) {
return r[r.length - 1] === a ? r : r.concat(a);
}, []);
console.log(result);
Or use Array#filter and an object for the last value.
var array = [1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2],
result = array.filter(function (a, i, aa) {
return this.last !== a && (this.last = a, true);
}, { last: undefined });
console.log(result);
What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Working Fiddle
This is a solution for ordered id with Array.prototype.reduce().
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');