Related
Okay so as the title says my goal is to find the least duplicate elements, given that the elements are only integers.
ex1: array = [1,1,2,2,3,3,3] result should be 1,2
ex2: array = [1,2,2,3,3,4] result should be 1,4
I could use the xor operator to find the elements that appear only once but since there might be only duplicates I cant.
I was thinking of first checking with XOR if the're any non-duplicate elements. If no proceed with fors to check for only two occurrences of the same element and so on, but that is not a good approach as its kinda slow,
any suggestions?
Another approach, using new Set() and few Array.prototype functions. If you have any questions, let me know.
var array1 = [1, 1, 2, 2, 3, 3, 3],
array2 = [1, 2, 2, 3, 3, 4];
function sort(arr) {
var filtered = [...new Set(arr)],
solution = [],
res = filtered.reduce(function(s, a) {
s.push(arr.filter(c => c == a).length);
return s;
}, []);
var minDupe = Math.min.apply([], res);
res.forEach((v, i) => v == minDupe ? solution.push(filtered[i]) : null)
console.log(solution)
}
sort(array1);
sort(array2);
Using Array#forEach instead of Array#reduce.
var array1 = [1, 1, 2, 2, 3, 3, 3],
array2 = [1, 2, 2, 3, 3, 4];
function sort(arr) {
var filtered = [...new Set(arr)],
solution = [],
res = [];
filtered.forEach(v => res.push(arr.filter(c => c == v).length));
var minDupe = Math.min.apply([], res);
res.forEach((v, i) => v == minDupe ? solution.push(filtered[i]) : null)
console.log(solution)
}
sort(array1);
sort(array2);
There may be a better or faster solution, but I would suggest to create a hash (object) with the integer as keys and the counts as values. You can create this in one loop of the array. Then, loop over the object keys keeping track of the minimum value found and add the key to the result array if it satisfies the minimum duplicate value.
Example implementation:
const counts = input.reduce((counts, num) => {
if (!counts.hasOwnProperty(num)) {
counts[num] = 1;
}
else {
counts[num]++;
}
return counts;
}, {});
let minimums = [];
let minCount = null;
for (const key in counts) {
if (!minimums.length || counts[key] < minCount) {
minimums = [+key];
minCount = counts[key];
}
else if (counts[key] === minCount) {
minimums.push(+key);
}
}
return minimums;
You can also simplify this a little bit using lodash: one operation to get the counts and another to get the minimum count and get the list of values that match that minimum count as a key:
import { countBy, invertBy, min, values } from "lodash";
const counts = countBy(input);
const minCount = min(values(counts));
return invertBy(counts)[minCount];
You could count the appearance, sort by count and delete all same max count keys. Then return the original values.
Steps:
declarate all variables, especial the hash object without any prototypes,
use the items as key got the hash table and if not set use an object with the original value and a count property,
increment count of actual hash,
get all keys from the hash table,
sort the keys in descending order of count,
get the count of the first element and store it in min,
filter all keys with min count,
get the original value for all remaining keys.
function getLeastDuplicateItems(array) {
var hash = Object.create(null), keys, min;
array.forEach(function (a) {
hash[a] = hash[a] || { value: a, count: 0 };
hash[a].count++;
});
keys = Object.keys(hash);
keys.sort(function (a, b) { return hash[a].count - hash[b].count; });
min = hash[keys[0]].count;
return keys.
filter(function (k) {
return hash[k].count === min;
}).
map(function (k) {
return hash[k].value;
});
}
var data = [
[1, 1, 2, 2, 3, 3, 3],
[1, 2, 2, 3, 3, 4],
[4, 4, 4, 6, 6, 4, 7, 8, 5, 5, 6, 3, 4, 6, 6, 7, 7, 8, 3, 3]
];
console.log(data.map(getLeastDuplicateItems));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A single loop solution with a variable for min and an array for collected count.
function getLeastDuplicateItems(array) {
var hash = Object.create(null),
temp = [],
min = 1;
array.forEach(function (a) {
var p = (temp[hash[a]] || []).indexOf(a);
hash[a] = (hash[a] || 0) + 1;
temp[hash[a]] = temp[hash[a]] || [];
temp[hash[a]].push(a);
if (min > hash[a]) {
min = hash[a];
}
if (p === -1) {
return;
}
temp[hash[a] - 1].splice(p, 1);
if (min === hash[a] - 1 && temp[hash[a] - 1].length === 0) {
min++;
}
}, []);
return temp[min];
}
var data = [
[1, 1, 2, 2, 3, 3, 3],
[1, 2, 2, 3, 3, 4],
[4, 4, 4, 6, 6, 4, 7, 8, 5, 5, 6, 3, 4, 6, 6, 7, 7, 8, 3, 3],
];
console.log(data.map(getLeastDuplicateItems));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 6 years ago.
Say I have the following two arrays:
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
I'd like to itterate over arrTwo and if it contains an element that is also in arrOne, remove it from arrTwo, and insert it in arrThree. So looking at the above arrays the state of the arrays afterwards should look like this:
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5];
var arrThree = [1, 4];
Could anyone point me in the right direction and the best way to go about this? If code is provided, a step-by-step explanation would really be appreciated so that I can understand what's going on.
A simple for loop, matching with indexOf and splicing matches.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
for (var i = 0; i < arrTwo.length; i++) {
if (arrOne.indexOf(arrTwo[i]) >= 0) {
arrThree.push(arrTwo[i]);
arrTwo.splice(i, 1);
i--;
}
}
console.log(arrOne, arrTwo, arrThree)
Array.IndexOf
Array.splice
Look into the Underscore library. All the elements in arrOne that are also in arrTwo is called _.intersection().
Use simple while loop with Array#splice and Array#unshift methods.
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = [];
// get length of array
var l = arrTwo.length;
// iterate over array from the end
while (l--) {
// check value present in arrOne
if (arrOne.indexOf(arrTwo[l]) > -1)
// if present then remove and insert it
// at the beginning of arrThree
arrThree.unshift(arrTwo.splice(l, 1)[0])
}
console.log(arrTwo, arrThree);
Hi You can use filter function to filter array.
try with below code.
var arrOne = [1, 4, 7];
var arrTwo = [2, 3, 5, 1];
var arrThree = [];
function checkValue(a) {
return !arrOne.indexOf(a);
}
function checkValue2(a) {
return arrThree.indexOf(a);
}
function myFunction() {
arrThree = arrTwo.filter(checkValue);
document.getElementById("demo").innerHTML = arrThree ;
arrTwo = arrTwo.filter(checkValue2);
document.getElementById("demo1").innerHTML = arrTwo;
}
var arrOne = [1, 4, 7];
var arrTwo = [1, 2, 3, 4, 5];
var arrThree = diff(arrOne,arrTwo);//passes the two arrays
console.log(arrThree);
function diff(one, two){
one.forEach(function(e1){ //iterate through the first array
two.forEach(function(e2){//iterate through second
if(e1 == e2) //checking if elements are equal
two.pop(e2);//removing from second array
});
});
return two; //returning new array
}
You can use underscore js for easy array operations, the difference operation will be _.difference([1, 2, 3, 4, 5], [5, 2, 10]);.
var array1 = [1, 2, 3, 4, 5, 6],
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var common = $.grep(array1, function(element) {
return $.inArray(element, array2) !== -1;
});
console.log(common); // returns [1, 2, 3, 4, 5, 6];
array2 = array2.filter(function(obj) {
return array1.indexOf(obj) == -1;
});
// returns [7,8,9];
Since the arrays are sorted you could read them in parallel : O(n) instead of O(n2). Don't use a library for such a simple problem, this is overkill :-)
var i = 0, j = 0;
var a = [1, 4, 7];
var b = [1, 2, 3, 4, 5];
var c = [];
while (i < a.length && j < b.length) {
if (a[i] < b[j]) i++;
else if (a[i] > b[j]) j++;
else c.push(b.splice(j, 1)[0]);
}
console.log("a " + toString(a));
console.log("b " + toString(b));
console.log("c " + toString(c));
function toString (v) {
return "[ " + v.join(" ") + " ]";
}
Trace :
#0 init
a = [ 1 4 7 ]
i
b = [ 1 2 3 4 5 ]
j
c = []
#1 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#2 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#3 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#4 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 4 5 ]
j
c = [ 1 ]
#5 a[i] = b[j] => move b[j] to c
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#6 a[i] < b[j] => increment i
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#7 a[i] > b[j] => increment j
a = [ 1 4 7 ]
i
b = [ 2 3 5 ]
j
c = [ 1 4 ]
#8 j = length of b => done
I need to delete occurrences of an element if it occurs more than n times.
For example, there is this array:
[20,37,20,21]
And the output should be:
[20,37,21]
I thought one way of solving this could be with the splice method
First I sort the array it order to make it like this:
[20,20,37,21]
Then I check if the current element is not equal to the next and split the array into chunks, so it should look like:
[20, 20],[37],[21]
Later I can edit the chunk longer than 1 and join it all again.
This is what the code looks like in my head but didn't work in real life
var array = [20, 37, 20, 21];
var chunk = [];
for(i = 0; i < array.length; i++) {
if(array[i] !== array[i + 1]) {
var index = array.indexOf(array[i]);
chunk.push = array.splice(0, index) // cut from zero to last duplicate element
} else
var index2 = a.indexOf(a[i]);
chunk.push(a.splice(0, index));
}
with this code the output is
[[], [20, 20]]
I think It's something in the 'else' but can't figure it out what to fix.
As the logic you want to achieve is to delete n occurrences of element in an array, your code could be as follow:
var array = [1, 1, 3, 3, 7, 2, 2, 2, 2];
var n = 2;
var removeMultipleOccurences = function(array, n) {
var filteredArray = [];
var counts = {};
for(var i = 0; i < array.length; i++) {
var x = array[i];
counts[x] = counts[x] ? counts[x] + 1 : 1;
if (counts[x] <= n) filteredArray.push(array[i])
}
return filteredArray;
}
console.log(removeMultipleOccurences(array, n));
I came up with this one, based on array filter checking repeated values up to a limit, but I can see #Basim's function does the same.
function removeDuplicatesAbove(arr, max) {
if (max > arr.length) {max = arr.length;}
if (!max) {return arr;}
return arr.filter(function (v, i) {
var under = true, base = -1;
for (var n = 0; n < max; n++) {
base = arr.indexOf(v, base+1); if (base == -1) {break;}
}
if (base != -1 && base < i) {under = false;}
return under;
});
}
var exampleArray = [20, 37, 20, 20, 20, 37, 22, 37, 20, 21, 37];
console.log(removeDuplicatesAbove(exampleArray, 3)); // [20, 37, 20, 20, 37, 22, 37, 21]
Always when you use splice() you truncate the array. Truncate the array with the length of same values from the start with the help of lastIndexOf(). It always starts from 0.
[ 1, 1, 1, 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 3, 4, 4, 5 ] // splice(0, 1)
[ 4, 4, 5 ] // splice(0, 2)
[ 5 ] // splice(0, 1)
Do this as long as the array length is greater than 0.
var arr = [1, 1, 1, 2, 2, 2, 3, 4, 4, 5];
var res = [];
while (arr.length > 0) {
var n = arr[0];
var last = arr.lastIndexOf(n) + 1;
res.push(n);
arr.splice(0, last);
}
console.log(res);
You can use Array.prototype.reduce(), Array.prototype.filter() to check if n previous elements are the same as current element
let cull = (arr, n) => arr.reduce((res, curr) => [...res
, res.filter(v => v === curr).length === n
? !1 : curr].filter(Boolean), []);
let arrays = [[20,37,20,21], [1,1,3,3,7,2,2,2,2]];
let cullone = cull(arrays[0], 1);
let cullthree = cull(arrays[1], 3);
console.log(cullone // [20, 37, 21]
, cullthree // [1, 1, 3, 3, 7, 2, 2, 2]
);
Lets say that I am to remove the oldest element of an array, because I wanted to replace it with a new value. (first-in-first-out).
For example, I have this array of values
var arr = [1,2,3,4,5,6,7]
And I wanted to only get the first three, values, and then on the 4th, replace the element who came first
[1,2,3], [4,2,3], [4,5,3] and so on..
I came up with a solution
var arr = [1,1,2,3,4,5,6,7];
var newArr = [];
for(i=0; i<arr.length; i++){
if(newArr.length == 3 && newArr.indexOf(arr[i]) < 0) {
newArr[i%3] = arr[i];
} else if(newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i])
}
console.log(newArr)
}
Which will render:
1
1
1,2
1,2,3
1,4,3
1,4,5
6,4,5
6,7,5
Instead of
1
1,2
1,2,3
4,2,3
4,5,3
4,5,6
7,5,6
What am I missing out.
var arr = [1, 1, 2, 3, 4, 5, 6, 7];
var newArr = [], currentIndex = 0;
for (i = 0; i < arr.length; i++) {
if (newArr.length === 3 && newArr.indexOf(arr[i]) < 0) {
newArr[currentIndex % 3] = arr[i];
currentIndex += 1;
} else if (newArr.indexOf(arr[i]) < 0) {
newArr.push(arr[i]);
}
console.log(newArr)
}
Output
[ 1 ]
[ 1 ]
[ 1, 2 ]
[ 1, 2, 3 ]
[ 4, 2, 3 ]
[ 4, 5, 3 ]
[ 4, 5, 6 ]
[ 7, 5, 6 ]
You just need to track the current index where you need to place the number using a separate variable.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Split array into chunks
I am trying to convert an array of values into a new array of paired values.
For example i need to convert:
var arr = [1,2,3,4,5,6,7,8];
into:
arr = [[1,2], [3,4], [5,6], [7,8]];
I tried using jQuery's .map() method like so but this did not work for me:
arr= $.map(arr, function(n, i){
return [n + ',' + n[ i + 1 ]];
});
If you insist on using map, you could do it like this:
arr= $.map(arr, function(n, i){
if (i%2 === 0) return [[n, arr[ i + 1 ]]];
});
If you don't want to use a hammer on a thumbtack:
var arr = [1,2,3,4,5,6,7,8];
var newarr = new Array();
for (var i=0; i<arr.length; i=i+2) {
newarr.push(arr.slice(i,i+2));
}
don't use jquery for every problem:
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
var narr = [];
for (i = 0; i < arr.length; i = i + 2) {
narr[i / 2] = [arr[i], arr[i + 1]];
}
but this only works if you have an even count of arr
Another example...
var arr = [1 , 2, 3, 4, 5, 6, 7, 8]
var final = []
while(arr.length) {
final.push(arr.splice(0, 2))
}
You don't want map, you want reduce.
Here is something that should work:
var endArr = [],
arr = [ 1, 2, 3, 4, 5, 6, 7, 8 ],
i = 0;
arr.reduce( function( prev, curr, index ) {
if ( index % 2 === 0 ) {
endArr[ i ] = [ prev, curr ];
}
i++;
} );
And just something else I thought about:
var endArr = [],
arr = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
while ( arr.length ) {
endArr.push( arr.splice( 0, 2 ) );
}
Edit: Arf, it's the same solution as Chris Gutierrez.