Get distinct duplicates from array - javascript

I have an array [1,1,1,1,2,3,4,5,5,6,7,8,8,8]
How can I get an array of the distinct duplicates [1,5,8] - each duplicate in the result only once, regardless of how many times it appears in the original array
my code:
var types = availControls.map(item => item.type);
var sorted_types = types.slice().sort();
availControlTypes = [];
for (var i = 0; i < sorted_types.length - 1, i++) {
if (sorted_types[i + 1] == sorted_types[i])
availControlTypes.push(sorted_types[i]);
}
This gets me the duplicates, but not unique.

This will do it
var input = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
let filterDuplicates = arr => [...new Set(arr.filter((item, index) => arr.indexOf(item) != index))]
console.log(filterDuplicates(input))

You need a for loop, with an object that will hold the number of times the number appeared in the array. When the count is already 1, we can add the item to the result. We should continue to increment the counter, so we won't add more than a single duplicate of the same number (although we can stop at 2).
function fn(arr) {
var counts = {};
var result = [];
var n;
for(var i = 0; i < arr.length; i++) {
n = arr[i]; // get the current number
if(counts[n] === 1) result.push(n); // if counts is exactly 1, we should add the number to results
counts[n] = (counts[n] || 0) +1; // increment the counter
}
return result;
}
var arr = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
var result = fn(arr);
console.log(result)

const dupes = arr =>
Array.from(
arr.reduce((acc, item) => {
acc.set(item, (acc.get(item) || 0) + 1);
return acc;
}, new Map())
)
.filter(x => x[1] > 1)
.map(x => x[0]);
const arr = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
console.log(dupes(arr));
// [ 1, 5, 8 ]

ES6 1 liner.
This is very similar to how we find unique values, except instead of filtering for 1st occurrences, we're filtering for 2nd occurrences.
let nthOccurrences = (a, n = 1) => a.filter((v, i) => a.filter((vv, ii) => vv === v && ii <= i).length === n);
let x = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
let uniques = nthOccurrences(x, 1);
let uniqueDuplicates = nthOccurrences(x, 2);
let uniqueTriplets = nthOccurrences(x, 3); // unique values with 3 or more occurrences
console.log(JSON.stringify(uniques));
console.log(JSON.stringify(uniqueDuplicates));
console.log(JSON.stringify(uniqueTriplets));

Related

A function that returns a new array, the values ​of this array must not be repeated more than n times

A task:
Write a function that takes an array and a number n. Then output an array in which there are no elements that are repeated more than n times.
Example:
Input:
n = 3;
arr = [1, 2, 4, 4, 4, 2, 2, 2, 2]
Output:
result = [1, 2, 4, 4, 4, 2, 2]
Tried to do something like that, but it's not working correctly.
let arr = [1, 2, 4, 4, 4, 2, 2, 2, 2];
let new_set = [...new Set(arr)];
let result = [];
console.log(new_set); // [1, 2, 4]
first:
for (let i = 0; i < arr.length; i++) {
if (arr[i] === arr[i - 1]) {
continue first;
}
else {
let count = 0;
for (let j = i; j < arr.length; j++) {
if ((arr[i] === arr[j]) && (count < 3)) {
result.push(arr[j]);
}
}
}
}
You need a persistent outer variable that keeps track of how many times an item has been iterated over so far. Once past the limit, don't push the item being iterated over to the result.
const arr = [1, 2, 4, 4, 4, 2, 2, 2, 2]
let n = 3;
const counts = {};
const result = [];
for (const item of arr) {
counts[item] = (counts[item] || 0) + 1;
if (counts[item] <= n) {
result.push(item);
}
}
console.log(result);
Another option, if you want to use Array.reduce.
It's not as optimised as #CertainPerformance as it uses a filter inside a loop. But for small arrays like this unlikely to make much difference.
const arr = [1, 2, 4, 4, 4, 2, 2, 2, 2]
let n = 3;
const result = arr.reduce((a,v)=>(
a.filter(f=>f===v).length < n ?a.push(v):a,a),[]);
console.log(result);
Code golf version using reduce and without array.filter:
const f=(n,a)=>a.reduce((({c={},r=[]},i)=>
(c[i]??=0,++c[i]>n?0:r.push(i),{c,r})),{}).r;
console.log(f(3, [1, 2, 4, 4, 4, 2, 2, 2, 2]).join());

Return the sum of all even integers in array squared (javascript)

As the title says, I am trying to take an array of numbers, and then return the sum of all the even numbers in the array squared.
I can get my function to return the sum of all the even numbers in a given array, but cannot get it to square the sum of the even numbers.
Here is what I have so far:
let numStr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squareEvenNumbers = (numStr) => {
let sum = 0;
for (let i = 0; i < numStr.length; i++) {
if (numStr[i] % 2 === 0) {
sum = Math.pow(sum + numStr[i], 2);
}
}
return sum
}
console.log(squareEvenNumbers(numStr));
You need to raise only the current item in the array to the power of 2, not the whole sum:
let numStr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squareEvenNumbers = (numStr) => {
let sum = 0;
for (let i = 0; i < numStr.length; i++) {
if (numStr[i] % 2 === 0) {
sum += Math.pow(numStr[i], 2);
}
}
return sum
}
console.log(squareEvenNumbers(numStr));
Or, more concisely:
let numStr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squareEvenNumbers = arr => arr
.filter(num => num % 2 === 0)
.reduce((a, num) => a + num ** 2, 0);
console.log(squareEvenNumbers(numStr));
Or, to only iterate over the array once:
let numStr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const squareEvenNumbers = arr => arr
.reduce((a, num) => a + (num % 2 === 0 && num ** 2), 0);
console.log(squareEvenNumbers(numStr));

Change order of a string using an array indexes/ Javascript

I am stuck with this challenge, any help would be great.
'Create a function that takes both a string and an array of numbers as arguments. Rearrange the letters in the string to be in the order specified by the index numbers. Return the "remixed" string.
Examples
remix("abcd", [0, 3, 1, 2]) ➞ "acdb"'
My attempt -
function remix(str, arr) {
var arr2 = [];
for (var i=0; i<str.length; i++){
arr2.splice(arr[i], 0, str[i]);
}
return arr2.join("");
}
This will solve some but not all of the tests.
EG.
("abcd", [0, 3, 1, 2]) = "acdb" but some do not.
EG.
"responsibility", [0, 6, 8, 11, 10, 7, 13, 5, 3, 2, 4, 12, 1, 9])
should be - "rtibliensyopis" mine is "rteislbpoyinsi"
You could use the value of arr[i] as target index for the actual letter.
function remix(str, arr) {
var result = [],
i;
for (i = 0; i < str.length; i++) {
result[arr[i]] = str[i];
}
return result.join('');
}
console.log(remix("abcd", [0, 3, 1, 2])); // "acdb"
console.log(remix("responsibility", [0, 6, 8, 11, 10, 7, 13, 5, 3, 2, 4, 12, 1, 9])) // "rtibliensyopis"
function myFunction(text, nums){
var arr = [];
for(var num in nums){
arr.push(text.charAt(nums[num]));
}
return arr;
};
I think this should work.
Edited answer - misinterpreted the question at first.
You can use Array.prototype.reduce to fill the positions in a new array with letters from str based on target positions from arr:
const remix = ( str, arr ) => (
arr.reduce( (acc, target, idx) => {
acc[target] = str[idx]; return acc;
}, [])
).join('');
or reduce the array of letters in str into an array:
const remix = ( str, arr ) => (
[...str].reduce( (acc, letter, idx) => {
acc[arr[idx]] = letter; return acc;
}, [])
).join('');

Find the least duplicate items in an array

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; }

Array truncation with splice method

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]
);

Categories