Related
How to completely remove repeated numbers from an array?
For example, if:
const array = [1, 1, 2, 3, 1, 2, 5]
The output should be:
[3, 5]
You could take an object for keeping track of seen items, by taking an array with the value or set the arrays value to zero.
Finally flat the result set to remove empty arrays.
const
array = [1, 1, 2, 3, 1, 2, 5],
result = array
.reduce((o => (r, v) => {
if (v in o) o[v].length = 0;
else r.push(o[v] = [v]);
return r;
})({}), [])
.flat();
console.log(result);
Roko and Ke1vans had answered in functional approaches. Both of them are correct. However, I'd show an answer in imperative approach, which may seems easier for new comer.
Similar to their flow. First, we count the occurrence of each number. Then we select the numbers that has occurred once (hence being non-repeated) into the output array.
let array = [1,1,2,3,1,2,5]
let counts = {}
let output = []
// loop each elements in the array as `item`
for(let item of array) {
// If the item is not set in the counts, `counts[item]` will be `undefined`.
// Using `|| 0` means use zero as fallback value if the items is unseen.
let count = counts[item] || 0
counts[item] = count + 1
}
// loop each keys in the object (key-value pairs) as `item`
for(let item in counts) {
let count = counts[item]
if(count == 1) {
// `+item` converts the key from string into number
output.push(+item)
}
}
console.log(output) // will print out `[ 3, 5 ]`
You can iterate and create a map of values. later iterate and filter.
const data = [1, 1, 2, 3, 1, 2, 5];
const findUniques = (data = []) => {
const map = data.reduce((m, num) => {
m[num] = (m[num] || 0) + 1;
return m;
}, {});
return data.filter((num) => map[num] === 1);
};
console.log(findUniques(data));
You can also do the same using 2 set, or 2 array.
const data = [1, 1, 2, 3, 1, 2, 5];
const findUniques2 = (data = []) => {
let unique = new Set();
let seen = new Set();
for (let num of data) {
if (seen.has(num)) unique.delete(num);
else unique.add(num);
seen.add(num);
}
return Array.from(unique);
};
console.log(findUniques2(data));
Use an Object where the key is the number, and the value is the number of occurrences. Than reduce it back to the desired array of values:
const arr = [1,1,2,3,1,2,5];
const res = Object.entries(arr.reduce((ob, v) => {
if (!(v in ob)) ob[v] = 0;
ob[v] += 1; // Count occurrences
return ob;
}, {})).reduce((arr, [k, v]) => { // Reduce back to Array
if (v === 1) arr.push(+k); // Only keys with 1 occurrence
return arr;
}, []);
console.log(res); // [3, 5]
You can use Array.filter() (Array filter article) for this for Example :
const a = [ 1 , 1 , 2 , 3 , 2 , 4 , 5 , 7];
function filter(value , index , array){
// looping through all the objects in the array
for(let i=0; i<array.length; i++) {
if(i != index && array[i] == value) return false; // return 'false' if the value has a duplicate other than itself
}
// return 'TRUE' if value hasn't been duplicated
return true;
}
const b = a.filter(filter); // [3, 4, 5, 7]
And the short version if this function's going to be used only once:
const a = [ 1 , 1 , 2 , 3 , 2 , 4 , 5 , 7];
const b = a.filter((value , index , array) => {
for(let i=0; i<array.length; i++) if(i != index && array[i] == value) return false;
return true;
});
// [3, 4, 5, 7]
You could find duplicates and then operate a difference.
let a = [1,1,2,3,1,2,5];
const findDuplicates = (nums) => {
nums.sort(); // alters original array
let ans = []
for(let i = 0; i< nums.length; i++){
if(nums[i] === nums[i+1]){
if(ans[ans.length -1] !== nums[i]){
ans.push(nums[i])
}
}
}
return ans;
}
duplicates = new Set(findDuplicates(a))
let difference = new Set([...a].filter(x => !duplicates.has(x)))
console.log(Array.from(difference))
output : [ 3, 5 ]
Note : I grab the findDuplicates function from this link
const data = [1, 1, 2, 3, 1, 2, 5];
const s = new Set();
const res = data.filter((a, i) => {
if (data.lastIndexOf(a) > i || s.has(a)) {
s.add(a);
return false;
}
return true;
});
console.log(res); //=> [3, 5]
I have a challenge to complete where I'm given an array [-1,4,-3,5,6,9,-2] and I need to get a new array that sorts the numbers in this order: [firstGreatest, firstLowest, secondGreatest, secondLowest ...and so on]. The negative and positive numbers may be different amount, as in 4 positive, 2 negative.
This is what I tried so far, but cannot think of a better solution.
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = ary.sort((a, b) => a - b)
const highest = sorted.filter(num => num > 0).sort((a, b) => b - a)
const lowest = sorted.filter(num => num < 0).sort((a, b) => b - a)
let copy = highest
for (let i = 0; i < highest.length; i++) {
for (let j = i; j < lowest.length; j++) {
if ([i] % 2 !== 0) {
copy.splice(1, 0, lowest[j])
}
}
}
}
console.log(arr)
someArray(arr)
console.log(arr)
You can easily solve this problem with two pointers algorithm.
O(n log n) for sorting
O(n) for add the value in result.
Take two-variable i and j,
i points to the beginning of the sorted array
j points to the end of the sorted array
Now just add the value of the sorted array alternatively in final result
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = arr.sort((a, b) => b - a);
// declaration
const result = [];
let i = 0,
j = sorted.length - 1,
temp = true;
// Algorithm
while (i <= j) {
if (temp) {
result.push(sorted[i]);
i++;
} else {
result.push(sorted[j]);
j--;
}
temp = !temp;
}
return result;
}
console.log(someArray(arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could sort the array and pop or shift until you have no more items.
function greatestLowest(array) {
let temp = [...array].sort((a, b) => a - b),
m = 'shift',
result = [];
while (temp.length) result.push(temp[m = { pop: 'shift', shift: 'pop' }[m]]());
return result;
}
console.log(...greatestLowest([-1, 2, -5, 3, 4, -2, 6]));
The general idea is to sort the array (highest to lowest) then pick the first and the last element until the array is empty. One way of doing it could be:
const input = [-1, 2, -5, 3, 4, -2, 6];
function someArray(arr) {
// sort the original array from highest to lowest
const sorted = arr.sort((a, b) => b - a);
const output = []
while (sorted.length > 0) {
// remove the first element of the sorted array and push it into the output
output.push(...sorted.splice(0, 1));
// [check to handle arrays with an odd number of items]
// if the sorted array still contains items
// remove also the last element of the sorted array and push it into the output
if (sorted.length > 0) output.push(...sorted.splice(sorted.length - 1, 1))
}
return output;
}
// test
console.log(`input: [${input.join(',')}]`);
console.log(`input (sorted desc): [${input.sort((a, b) => b - a).join(',')}]`)
console.log(`output: [${someArray(input).join(',')}]`);
This is a simple and a shorter method:
function makearray(ar) {
ar = points.sort(function(a, b) {
return b - a
})
let newarray = []
let length = ar.length
for (let i = 0; i < length; i++) {
if (i % 2 == 0) {
newarray.push(ar[0])
ar.splice(0, 1)
} else {
newarray.push(ar[ar.length - 1])
ar.splice(ar.length - 1, 1)
}
}
return newarray
}
const points = [-1, 2, -5, 3, 4, -2, 6]
console.log(makearray(points))
I have an array a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7]
I want to fetch all the duplicate pair in this array list.
Since there are pairs of 2 and 7 the output should be -
Output: [2, 7]
I tried writing my own logic but I am very weak in that area. Can somebody help?
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
for (let i = 0; i < sorted_arr.length; i++) {
let matchingElementCount = 1;
for (let j = i + 1; j < sorted_arr.length - i; j++) {
if (sorted_arr[j] === sorted_arr[i]) {
++matchingElementCount;
} else {
if(matchingElementCount % 2 === 0) {
results.push(sorted_arr[i]);
}
i = j - 1;
break;
}
}
}
return results; } var a = [1,1,1,2,2,3,3,3,4,6,6,6,7,7]; var duplicateValues= getDuplicateArrayElements(a);
You can achieve your result by using reduce and forEach.
const arr = [1,1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
// Generate a hashmap from the given array for counting the frequency.
const hashMap = arr.reduce((a, c) => {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
const pair = [];
// If the frequency is divided by 2 then push the key of the hashMap into pair array.
Object.entries(hashMap).forEach(([k, v]) => {
if (v % 2 === 0) {
[...Array(Math.floor(v / 2))].forEach(_ => pair.push(k));
}
})
console.log(pair);
You can grab the frequency of each number, and then filter out any which have an odd frequency. You can then .flatMap() the frequencies to an array containing your number for each pair you found like so:
const a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
const freq = a.reduce((m, n) => m.set(n, (m.get(n) || 0) + 1), new Map);
const res = [...freq].filter(([n, count]) => count % 2 == 0).flatMap(([n, c]) => Array(c/2).fill(n));
console.log(res);
This way, if you have four 1s (ie: two pairs of 1s), the filter will pick up on that, allowing you to flat-map the [1, 4] array to an array of [1, 1], which is merged into the larger resulting array.
You could create a helper map and keep the counts of each number as the values and the numbers itself as the keys. After iterating through the array, you only need to find the ones with a count divisible by 2:
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7]
function findDuplicates(arr) {
const map = {};
for (const curr of arr) {
if (!map[curr]) {
map[curr] = 0;
}
map[curr]++;
}
const res = [];
for (const key in map) {
if (map.hasOwnProperty(key) && map[key] % 2 === 0) {
res.push(Number.parseInt(key));
}
}
return res;
}
console.log(findDuplicates(a));
You can first count the occurrence of each numbers and if it is greater than 0 and divisible by 2 then add these to final result else don't
function getDuplicateArrayElements(arr) {
let map = {}
let results = [];
for (let num of arr) {
map[num] = map[num] || 0
map[num]++
}
return Object.keys(map)
.filter(v => map[v] && map[v] % 2 === 0)
.map(v => new Array(map[v]/2).fill(+v))
.flat()
.sort()
}
var a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 7, 7,8,8,8,8];
var duplicateValues = getDuplicateArrayElements(a);
console.log(duplicateValues)
const a = {};
[1,1,1,2,2,3,3,3,4,6,6,6,7,7].forEach(v => {a[v] = a[v] ? a[v] + 1 : 1});
const l = [];
Object.keys(a).forEach(k => !(a[k] % 2) && l.push(k));
Here you go:
function getDuplicateArrayElements(arr){
var dupilcates=arr.filter(x => arr.filter(y=>y==x).length==2);
var found=[];
for(var i=0;i<dupilcates.length;i=i+2)
found.push(dupilcates[i]);
return found;
}
This will give you the desired pairs. with [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7] input it will return [1,1,2,6,6,7]:
function getDuplicateArrayElements(arr){
let sorted_arr = arr.slice().sort();
let results = [];
let i = 0;
while (i < sorted_arr.length) {
let counter = 1;
let j = i;
while (sorted_arr[j] === sorted_arr[j+1]) {
counter++;
j++;
}
if (counter%2 == 0) {
results.push(...Array(counter/2).fill(sorted_arr[i]))
}
i += counter;
}
return results;
}
var a = [1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 6, 6, 6, 6, 7, 7];
console.log(getDuplicateArrayElements(a));
Another rather concise solution:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
uniques = new Set(a); //filter out duplicates
res = [];
uniques.forEach((key)=>{
if(a.filter(elem => elem === key).length === 2){res.push(key)};
//filter out only the elements which match the key being tested
//if there are 2, push to result
})
Edit: even more concise, but perhaps less efficient:
a = [1,1,1,2,2,3,3,3,4,4,4,6,6,6,7,7];
res = Array.from(new Set(a.filter(elem => a.filter(el => el === elem).length === 2)));
Javascript has awesome JSON object, in my opinion, you can use json as a dictionary;
{ key: _value }.
Loop throw array one times, no sort, no slice
key is array's element value, _value is frequency
var frequencies = {};
for (let i = 0; i < a.length; a++) {
if (result[a[i]] == 'over') continue;
if (result[a[i]] == undefined) { // First times
result[a[i]] = 1
} else if (result[a[i]] == 1) { // Second times
result[a[i]] = 2
} else { // Ignore if > 2
result[a[i]] = 'over'
}
}
// result: {1: "over", 2: 2, 3: "over", 4: "over", 6: "over", 7: 2}
so now pick keys have value equal 2
function getDuplicateArrayElements(numbers: number[]): number[] {
const occurences = new Map<number, number>();
for (let number of numbers) {
if (occurences.has(number)) {
const current = occurences.get(number)!;
occurences.set(number, current + 1);
} else
occurences.set(number, 1)
}
return (
Array
.from(occurences.entries())
.reduce<number[]>(
(accumulator, [key, value]) => {
if (value === 2) {
return accumulator.concat(key)
}
return accumulator
},
[]
)
)
}
const a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6, 6, 6, 7, 7];
getDuplicateArrayElements(a); // [2, 7]
I'm basically looking for a simpler way to do this:
heights.forEach((height, i) => {
var p = i > 0 ? i -1 : 0;
this.breakingPoints.push(height+heights[p])
})
If I input an array that is:
[0,2,5,5]
I would like to output
[0,2,7,12]
You could use map() method with closure to return new array.
const arr = [0,2,5,5];
const result = (s => arr.map(e => s += e))(0);
console.log(result)
You can simply store the variable to push in a variable which will allow you to automatically sum the new value to it without checking the index.
var total = 0;
heights.forEach(height => {
this.breakingPoints.push(total += height);
})
The result would be:
[0, 2, 7, 12]
You can use Array.reduce method.
let inputArray = [1, 2, 3, 4];
let outputArray = [];
inputArray.reduce(function(accumulator, currentValue, currentIndex) {
return outputArray[currentIndex] = accumulator + currentValue; }, 0);
You could use reduce and spread operator to concat values:
const input = [0, 2, 5, 5];
const output = input.reduce((acc, val) => [...acc, (acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val],[]);
Or when using < ES6
var output = input.reduce(function (acc, val) { return acc.concat([(acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val]); }, []);
I want to split an array into pairs of arrays.
var arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
would be
var newarr = [
[2, 3],
[4, 5],
[6, 4],
[3, 5],
[5]
]
You can use js reduce
initialArray.reduce(function(result, value, index, array) {
if (index % 2 === 0)
result.push(array.slice(index, index + 2));
return result;
}, []);
Lodash has a method for this: https://lodash.com/docs/4.17.10#chunk
_.chunk([2,3,4,5,6,4,3,5,5], 2);
// => [[2,3],[4,5],[6,4],[3,5],[5]]
There's no pre-baked function to do that, but here's a simple solution:
var splitPairs = function(arr) {
var pairs = [];
for (var i=0 ; i<arr.length ; i+=2) {
if (arr[i+1] !== undefined) {
pairs.push ([arr[i], arr[i+1]]);
} else {
pairs.push ([arr[i]]);
}
}
return pairs;
};
Yet another that's a bit of a mish-mash of the already-posted answers. Adding it because having read the answers I still felt things could be a little easier to read:
var groups = [];
for(var i = 0; i < arr.length; i += 2)
{
groups.push(arr.slice(i, i + 2));
}
There is now the flexible Array#flatMap(value, index, array):
const pairs = arr.flatMap((_, i, a) => i % 2 ? [] : [a.slice(i, i + 2)]);
And the possibly more efficient, but goofy looking Array.from(source, mapfn?):
const pairs = Array.from({ length: arr.length / 2 }, (_, i) => arr.slice(i * 2, i * 2 + 2))
It's possible to group an array into pairs/chunks in one line without libraries:
function chunks(arr, size = 2) {
return arr.map((x, i) => i % size == 0 && arr.slice(i, i + size)).filter(x => x)
}
console.log(chunks([1, 2, 3, 4, 5, 6, 7])) // -> [[1, 2], [3, 4], [5, 6], [7]]
Here's a good generic solution:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
For your case, you can call it like this:
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
The inplace argument determines whether the operation is done in-place or not.
Here's a demo below:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
disp(newarr);
// or we can do it in-place...
splitInto(arr, 3, true);
disp(arr);
function disp(array) {
var json = JSON.stringify(array);
var text = document.createTextNode(json);
var pre = document.createElement('pre');
pre.appendChild(text);
document.body.appendChild(pre);
}
A slightly different approach than using a for loop for comparison. To avoid modifying the original array slice makes a shallow copy since JS passes objects by reference.
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
var array = [2,3,4,5,6,4,3,5,5];
var newArr = pairArray(array);
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
document.write('<pre>' + JSON.stringify(newArr) + '</pre>');
I would use lodash for situations like this.
Here is a solution using _.reduce:
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
var arr = [2,3,4,5,6,4,3,5,5];
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
document.write(JSON.stringify(newArr)); // [[2,3],[4,5],[6,4],[3,5],[5]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
Here's another solution using lodash helpers:
function toPairs(array) {
const evens = array.filter((o, i) => i % 2);
const odds = array.filter((o, i) => !(i % 2));
return _.zipWith(evens, odds, (e, o) => e ? [o, e] : [o]);
}
console.log(toPairs([2,3,4,5,6,4,3,5,5]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
const items = [1, 2, 3, 4, 5];
const createBucket = (bucketItems, bucketSize) => buckets => {
return bucketItems.length === 0 ? buckets : [...buckets, bucketItems.splice(0, bucketSize)];
};
const bucketWithItems = items.reduce(createBucket([...items], 4), []);
Here is a short and more generic solution:
function splitArrayIntoPairs(arr, n) {
var len = arr.length
var pairs = []
for (let i = 0; i < len; i += n) {
var temp = []
for (var j = i; j < (i + n); j++) {
if (arr[j] !== undefined) {
temp.push(arr[j])
}
}
pairs.push(temp)
}
return pairs
}
Where arr is your array and n is no of pairs
This combines some of the answers above but without Object.fromEntires. The output is similar to what you would get with minimist.
const splitParameters = (args) => {
const split = (arg) => (arg.includes("=") ? arg.split("=") : [arg]);
return args.reduce((params, arg) => [...params, ...split(arg)], []);
};
const createPairs = (args) =>
Array.from({ length: args.length / 2 }, (_, i) =>
args.slice(i * 2, i * 2 + 2)
);
const createParameters = (pairs) =>
pairs.reduce(
(flags, value) => ({
...flags,
...{ [value[0].replace("--", "")]: value[1] }
}),
{}
);
const getCliParameters = (args) => {
const pairs = createPairs(splitParameters(args));
const paramaters = createParameters(pairs);
console.log(paramaters);
return paramaters;
};
//const argsFromNodeCli = process.argv.slice(2); // For node
const testArgs = [
"--url",
"https://www.google.com",
"--phrases=hello,hi,bye,ok"
];
const output = getCliParameters(testArgs);
document.body.innerText = JSON.stringify(output);
Here is another concise but still efficient solution using modern JavaScript (arrow function, Array.prototype.at):
splitPairs = arr =>
arr.reduce((pairs, n, i) =>
(i % 2 ? pairs.at(-1).push(n)
: pairs.push([n]),
pairs), []);
It is (memory-)efficient because it just creates one array for the result and one array for each pair and then modifies them. The case where there is an odd number of elements is handled naturally.
When minified, it is also really concise code:
splitPairs = a=>a.reduce((p,n,i)=>(i%2?p.at(-1)[1]=n:p.push([n]),p),[]);
Using ES6 features:
const arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
const result = arr.slice(arr.length/2).map((_,i)=>arr.slice(i*=2,i+2))
console.log(result)
Here is another generic solution that uses a generator function.
/**
* Returns a `Generator` of all unique pairs of elements from the given `iterable`.
* #param iterable The collection of which to find all unique element pairs.
*/
function* pairs(iterable) {
const seenItems = new Set();
for (const currentItem of iterable) {
if (!seenItems.has(currentItem)) {
for (const seenItem of seenItems) {
yield [seenItem, currentItem];
}
seenItems.add(currentItem);
}
}
}
const numbers = [1, 2, 3, 2];
const pairsOfNumbers = pairs(numbers);
console.log(Array.from(pairsOfNumbers));
// [[1,2],[1,3],[2,3]]
What I like about this approach is that it will not consume the next item from the input until it actually needs it. This is especially handy if you feed it a generator as input, since it will respect its lazy execution.