Check if at least two array values are equal - javascript

I'm actually looking for a way to check if two values of an array or more are equal. Here are some examples :
[1, 2, 3] // false
[1, 1, 5] // true
['a', 'b', 'a', 'c'] // true
[10, 10, 10] // true
I found this function that gives 'true' if EVERY array values are equal, but that's not what i'd like :
[1,1,1,1].every( (val, i, arr) => val === arr[0] ) // true

You can use a Set to eliminate duplicates:
const nonUnique = a => new Set(a).size !== a.length;
console.log(nonUnique([1, 2, 3])); // false
console.log(nonUnique([1, 1, 5])); // true
console.log(nonUnique(['a', 'b', 'a', 'c'])); // true
console.log(nonUnique([10, 10, 10])); // true

One simple way would be create a Set of the unique values and compare size of Set to length of array
const hasDuplicates = (arr) => new Set(arr).size < arr.length ;
console.log(hasDuplicates([1, 2, 3]));
console.log(hasDuplicates([1, 1, 5]));
console.log(hasDuplicates(['a', 'b', 'a', 'c']));
console.log(hasDuplicates([10, 10, 10]));

This algorithm is pretty inefficient (O(n^2), brute force search), but it works:
function has_dupes(arr) {
return arr.some((x, i) => arr.includes(x, i+1));
}
console.log(has_dupes([1, 2, 3]));
console.log(has_dupes([1, 1, 5]));
console.log(has_dupes(['a', 'b', 'a', 'c']));
console.log(has_dupes([10, 10, 10]));
For every element x at some index i, we check whether the subarray starting at i+1 includes another value that's equal to x.

Using a for loop we can break the loop once we find a duplicate.
var a = [1, 2, 3] // false
var b = [1, 1, 5] // true
var c = ['a', 'b', 'a', 'c'] // true
var d = [10, 10, 10] // true
function diff(arr){
var diff = []
for(let i = 0; i<arr.length; i++){
if(diff.includes(arr[i])){
return true;//<-- break the loop
}else{
diff.push(arr[i]);
}
}
return false;
}
console.log(diff(a))
console.log(diff(b))
console.log(diff(c))
console.log(diff(d))

You could use a double for loop where one is the index of what is being looked for and the inner loop checking for a duplicate.

You can find all unique elements through lodash and just compare the size of both the arrays to get what you want.
a = [1, 2, 3]
a_uniq = _.uniq(a); //will return [1, 3]
console.log(a.length != a_uniq.length); //will return false
a = [1, 1, 3]
a_uniq = _.uniq(a); //will return [1, 3]
console.log(a.length != a_uniq.length); //will return true
Can test here quickly: https://codepen.io/travist/full/jrBjBz/

Reduce the array into an object with keys being the items. If the object's keys are a different length than the items length, there are duplicates.
This also gives you an indication of the number of duplicates.
const items1 = [1, 2, 3, 3, 4]
const items2 = [1, 2, 3, 3, 3, 3, 4]
const items3 = [1, 2, 3, 4]
const items4 = [undefined, undefined]
function dupCount(array) {
const obj = array.reduce((acc, item) => {
acc[item] = true;
return acc;
}, {})
return array.length - Object.keys(obj).length
}
console.log(dupCount(items1))
console.log(dupCount(items2))
console.log(dupCount(items3))
console.log(dupCount(items4))

function isSameArray(data, count) {
var result = false;
data.forEach(a => {
const filter = data.filter(f => f === a);
if (filter.length > count - 1) {
result = true;
return;
}
});
return result;
}
isSameArray([1, 2, 3], 2)

Add them to a set while checking using the find method
let items1 = [1, 2, 3, 3, 4];
let items2 = [1, 2, 3, 4];
let items3 = ['a', 'b', 'a', 'c']
let items4 = [0, 0]
let items5 = [undefined, undefined]
function hasDuplicate(array) {
const set = new Set()
return array.some(it => {
if (set.has(it)) {
return true
} else {
set.add(it);
return false;
}
})
}
console.log(hasDuplicate(items1))
console.log(hasDuplicate(items2))
console.log(hasDuplicate(items3))
console.log(hasDuplicate(items4))
console.log(hasDuplicate(items5))

You can loop it easily using for loop for example:-
function hasDuplicate(lst){
for(var i=0; i<lst.length; i++)
for(var j=i+1; j<lst.length;j++)
if(i!=j && lst[i] === lst[j])
return true;
return false;
}
var list1 = [1,1,5];
window.alert(hasDuplicate(list1)); //True

Array.some works the same as Array.every, except if the test passes true for one of the items in the array you're iterating over, execution stops and it returns true. Probably what you're looking for.

The following will help you in achieving the result which u gave as an example:
Array_is_true(int *a,int n)
{
int j=1,flag=0;
for(int i=0,i<n;i++)
{
j=i+1;
while(j<n;)
{
if(a[i]==a[j])
{ flag=1;j++;}
}
}
}

Related

How can I reverse the "includes()" method to "not-includes()" and retrieve the not included value?

Im trying to retrieve the not included value in the second array, by using the following code:
function diffArray(arr1, arr2) {
var newArr = [];
for (let i of arr1) {
if (arr2.includes(i)) {
newArr.push(i)
}
}
return newArr
}
console.log(
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5])
)
Is there any way I can use another method to do this. I tried indexOf but I don't want the index.
Thank you
You can use filter():
let arr1 = [1, 2, 3, 5];
let arr2 = [1, 2, 3, 4, 5];
let result = arr2.filter(a2 => !arr1.includes(a2));
console.log(result);
if (!arr2.includes(i)) {
newArr.push(i)
}
! means not
You could always use else as well, but it's more lines of code:
if (arr2.includes(i)) {
// newArr.push(i)
} else {
newArr.push(i);
}
const a1 = [1, 2, 3, 4, 5];
const a2 = [1, 2, 3, 5];
function diffArray(arr1, arr2) {
const frequencies = arr1.concat(arr2).reduce((frequencies, number) => {
const frequency = frequencies[number];
frequencies[number] = frequency ? frequency + 1 : 1;
return frequencies;
}, {});
return Object.keys(frequencies).filter(number => frequencies[number] === 1);
}

Alternating values from two arrays into a new third array

I'm on my third week of learning Javascript and got an assignment that's giving me some trouble.
I'm supposed to create a function called mix that takes two parameters that are two arrays. When called the function should return a new list which alternates between the two previous arrays (see example below).
This is about arrays and loops so I need to use those. also, I'm only allowed to use the array functions: push, pop, shift & unshift.
My teacher said that this is solved the easiest using a while loop.
Example
mix([], []) === []
mix([2, 4], []) === [2, 4]
mix([], [8, 16]) === [8, 16]
mix([1, 3, 5], [2, 4]) === [1, 2, 3, 4, 5]
mix([10, 9], ['a', 'b', 'c']) === [10, 'a', 9, 'b', 'c']
Before I got the tip about the easiest being a while loop I started trying with a for a loop. The problem I'm having here is that it works as long as the arrays are the same length, but I'm having trouble understanding how I can solve it so the arrays can have different lengths.
Since I'm trying to learn I want pointers in the right direction and not the whole answer!
Please excuse my chaotic beginner code :)
My current code
function mix(array1, array2) {
let newList = [];
for(i = 0; i < array1.length || i < array2.length; i++) {
if(array1.length > 0 || array2.length > 0){
newList.push( array1[i] );
newList.push( array2[i] );
}
}
return newList;
}
mix([10, 9],['a', 'b', 'c'])
I would also like a pointer for how a while loop would be easier and how i would go about using that instead.
Thanks in advance!
To fix your current code, you need to separately check whether i < array1.length (and if so, push array1[i]), and also do the same sort of test for array2:
function mix(array1, array2) {
let newList = [];
for (let i = 0; i < array1.length || i < array2.length; i++) {
if (i < array1.length) {
newList.push(array1[i]);
}
if (i < array2.length) {
newList.push(array2[i]);
}
}
return newList;
}
console.log(mix([10, 9], ['a', 'b', 'c']));
Make sure to declare the i with let i, else you'll implicitly create a global variable (or throw an error in strict mode).
To do this with a while loop, I'd loop while either array has a length, and shift (remove the [0]th item) from them:
function mix(array1, array2) {
const newList = [];
while (array1.length || array2.length) {
if (array1.length) {
newList.push(array1.shift());
}
if (array2.length) {
newList.push(array2.shift());
}
}
return newList;
}
console.log(mix([10, 9], ['a', 'b', 'c']));
You can do much better with array shift, it takes first element from array and returns its value, so for example
const firstElement = [1, 2, 4].shift();
// firstElement - 1
// array [2, 4]
with this info you can now write your function like so:
function (arr1, arr2) {
const resultArr = [];
while(arr1.length && arr2.length) {
resultArr.push(arr1.shift());
resultArr.push(arr2.shift());
}
return resultArr.concat(arr1, arr2);
}
You can achieve it using Array.prototype.shift(), Array.prototype.push() and Spread syntax
function mix(arr1,arr2) {
var newArr=[];
while(arr1.length>0&&arr2.length>0) {
newArr.push(arr1.shift(),arr2.shift());
}
newArr.push(...arr1,...arr2);
return newArr;
}
An alternative approach could be to consider the input arrays as a two-dimensional array.
You can then:
rotate/transpose the two-dimensional array (rows become columns); and
flatten the result (rows are concatenated into a one-dimensional array).
The transformation looks like this for the example input [1, 3, 5], [2, 4]:
Rotate Flatten
[1, 3, 5], ⇒ [1, 2], ⇒ [1, 2, 3, 4, 5]
[2, 4] [3, 4],
[5]
Or, in code:
const mix = (...arrays) => {
const transposed = arrays.reduce((result, row) => {
row.forEach((value, i) => result[i] = [...result[i] || [], value]);
return result;
}, []);
return transposed.flat();
};
console.log(mix([], [])); // === []
console.log(mix([2, 4], [])); // === [2, 4]
console.log(mix([], [8, 16])); // === [8, 16]
console.log(mix([1, 3, 5], [2, 4])); // === [1, 2, 3, 4, 5]
console.log(mix([10, 9], ['a', 'b', 'c'])); // === [10, 'a', 9, 'b', 'c']
Benefits of this approach are that it automatically scales to allow more than two input arrays, and, unlike the shift operations, does not mutate the input arrays.

How to check if two int arrays are permutations in JavaScript

How can I check if two integers arrays are permutations? I need to do it in JavaScript.
For example, I have two arrays:
a = [1, 2, 3, 4, 5]
and
b = [2, 3, 5, 1, 4]
I need the program to return true.
You could use a Map to store the occurrence count and then decrease that count whenever you find a mapping occurrence in the other array:
function isPermutation(a, b) {
if (a.length !== b.length) return false;
let map = new Map(a.map(x => [x, { count: 0 }]));
a.forEach(x => map.get(x).count++);
return b.every(x => {
let match = map.get(x);
return match && match.count--;
});
}
let a =[1,2,3,4,5,1];
let b = [2,3,1,5,1,4];
console.log(isPermutation(a, b));
The lazy solution:
let a = [1,2,3,4,5],
b = [2,3,5,1,4];
let res = JSON.stringify(a.sort()) === JSON.stringify(b.sort())
console.log(res)
The more efficient solution:
function perm (a,b) {
let map = a.reduce((acc,c) => {acc[c] = (acc[c] || 0) + 1; return acc},{})
for (el of b) {
if (!map[el] || map[el] == 0) {
return false;
} else {
map[el]--;
}
}
for (k in map) {
if (map[k] != 0) {
return false;
}
}
return true;
}
console.log(perm([1, 2, 3, 4, 5],[2, 3, 5, 1, 4])) // => true
console.log(perm([1, 2, 3, 4, 5, 5, 5],[2, 3, 5, 1, 4])) // => false
console.log(perm([1,1,2],[1,2,2])) // => false
console.log(perm([1,2,3,4,5,1],[2,3,1,5,1,4])) // => true
This solution is in hindsight similar to the one of #trincot but I guess slightly different enough to keep it posted.
The idea is the following: We create a map from the first array via reduce where the value is a count of occurrences. We then take the other array and subtract occurrences from the respective keys of map. If the key doesn't exist is or the value is already zero, we know this is not a permutation. Afterwords we loop the map, checking whether all values are exactly zero.
var a = [1, 2, 3, 4, 5];
var b = [2, 3, 5, 1, 4];
return a.filter(x => !b.includes(x)).length === 0
This will return true if all of the values in a exists in b, regardless of position.
This worked:
var a =[1,2,3,4,5,1];
var b = [2,3,1,5,1,4];
console.log(a.sort().toString() === b.sort().toString())

Remove elements from array using javascript filter

I have two arrays and want to remove duplicates using filter function.
Here is my code:
arr1 = [1, 2, 3, 1, 2, 3];
arr2 = [2, 3];
result = [1, 1];
var result = arr1.filter(function(value, index) {
for (var i = 0; i <= arr2.length; i++) {
if (value !== arr2[i]) {
return value === arr2[i];
}
}
}
Thanks in advance! Any help would be great!
You can try to convert arguments into array and then check if the value from the initial array is in arguments array:
function destroyer(arr) {
// Converting arguments into array
var args = Array.prototype.slice.call(arguments);
arr = arr.filter(function (val) {
return args.includes(val)===false;
});
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3); // returns[1,1]
First of all, if its not a problem adding a library. I am using uniq from underscore.js.
uniq_.uniq(array, [isSorted], [iteratee]) Alias: unique
Produces a duplicate-free version of the array, using === to test object
equality. In particular only the first occurence of each value is
kept. If you know in advance that the array is sorted, passing true
for isSorted will run a much faster algorithm. If you want to compute
unique items based on a transformation, pass an iteratee function.
_.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]
Other solution is using pure JS:
var newArray = [1, 2, 2, 3, 3, 4, 5, 6];
var unique = newArray.filter(function(itm, i, a) {
return i == newArray.indexOf(itm);
});
alert(unique);
But first you will need to combine your arrays in a new array:
var newArray = arr1.concat(arr2);
JS Fiddle
I hope this helped! :)
Here's one way without the filter function:
var arr1 = [1, 2, 3, 1, 2, 3];
var newArr = [];
for(var i = 0;i < arr1.length;i++){
if (newArr.indexOf(arr1[i]) === -1) {
newArr.push(arr1[i]);
}
}
Just use Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
with Array.prototype.indexOf()
The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.
var arr1 = [1, 2, 3, 1, 2, 3],
arr2 = [2, 3],
result = arr1.filter(function (a) {
return !~arr2.indexOf(a);
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
As in this JS Fiddle, using filter()
arr1 = [1, 2, 3, 1, 2, 3];
arr2 = [2, 3];
result = [1, 1];
var result = arr1.filter(myFunc);
function myFunc(value) {
for (var i = 0; i < arr2.length; ++i) {
// to remove every occurrence of the matched value
for (var j = arr1.length; j--;) {
if (arr1[j] === arr2[i]) {
// remove the element
arr1.splice(j, 1);
}
}
}
}
document.getElementById('result').innerHTML = arr1;
console.log(arr1);
// Output: [1,1]
<div id="result"></div>

Counting the occurrences / frequency of array elements

In Javascript, I'm trying to take an initial array of number values and count the elements inside it. Ideally, the result would be two new arrays, the first specifying each unique element, and the second containing the number of times each element occurs. However, I'm open to suggestions on the format of the output.
For example, if the initial array was:
5, 5, 5, 2, 2, 2, 2, 2, 9, 4
Then two new arrays would be created. The first would contain the name of each unique element:
5, 2, 9, 4
The second would contain the number of times that element occurred in the initial array:
3, 5, 1, 1
Because the number 5 occurs three times in the initial array, the number 2 occurs five times and 9 and 4 both appear once.
I've searched a lot for a solution, but nothing seems to work, and everything I've tried myself has wound up being ridiculously complex. Any help would be appreciated!
Thanks :)
You can use an object to hold the results:
const arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const counts = {};
for (const num of arr) {
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
console.log(counts);
console.log(counts[5], counts[2], counts[9], counts[4]);
So, now your counts object can tell you what the count is for a particular number:
console.log(counts[5]); // logs '3'
If you want to get an array of members, just use the keys() functions
keys(counts); // returns ["5", "2", "9", "4"]
const occurrences = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
return acc[curr] ? ++acc[curr] : acc[curr] = 1, acc
}, {});
console.log(occurrences) // => {2: 5, 4: 1, 5: 3, 9: 1}
const arr = [2, 2, 5, 2, 2, 2, 4, 5, 5, 9];
function foo (array) {
let a = [],
b = [],
arr = [...array], // clone array so we don't change the original when using .sort()
prev;
arr.sort();
for (let element of arr) {
if (element !== prev) {
a.push(element);
b.push(1);
}
else ++b[b.length - 1];
prev = element;
}
return [a, b];
}
const result = foo(arr);
console.log('[' + result[0] + ']','[' + result[1] + ']')
console.log(arr)
One line ES6 solution. So many answers using object as a map but I can't see anyone using an actual Map
const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());
Use map.keys() to get unique elements
Use map.values() to get the occurrences
Use map.entries() to get the pairs [element, frequency]
var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());
console.info([...map.keys()])
console.info([...map.values()])
console.info([...map.entries()])
If using underscore or lodash, this is the simplest thing to do:
_.countBy(array);
Such that:
_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}
As pointed out by others, you can then execute the _.keys() and _.values() functions on the result to get just the unique numbers, and their occurrences, respectively. But in my experience, the original object is much easier to deal with.
Don't use two arrays for the result, use an object:
a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
result = { };
for(var i = 0; i < a.length; ++i) {
if(!result[a[i]])
result[a[i]] = 0;
++result[a[i]];
}
Then result will look like:
{
2: 5,
4: 1,
5: 3,
9: 1
}
How about an ECMAScript2015 option.
const a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const aCount = new Map([...new Set(a)].map(
x => [x, a.filter(y => y === x).length]
));
aCount.get(5) // 3
aCount.get(2) // 5
aCount.get(9) // 1
aCount.get(4) // 1
This example passes the input array to the Set constructor creating a collection of unique values. The spread syntax then expands these values into a new array so we can call map and translate this into a two-dimensional array of [value, count] pairs - i.e. the following structure:
Array [
[5, 3],
[2, 5],
[9, 1],
[4, 1]
]
The new array is then passed to the Map constructor resulting in an iterable object:
Map {
5 => 3,
2 => 5,
9 => 1,
4 => 1
}
The great thing about a Map object is that it preserves data-types - that is to say aCount.get(5) will return 3 but aCount.get("5") will return undefined. It also allows for any value / type to act as a key meaning this solution will also work with an array of objects.
function frequencies(/* {Array} */ a){
return new Map([...new Set(a)].map(
x => [x, a.filter(y => y === x).length]
));
}
let foo = { value: 'foo' },
bar = { value: 'bar' },
baz = { value: 'baz' };
let aNumbers = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4],
aObjects = [foo, bar, foo, foo, baz, bar];
frequencies(aNumbers).forEach((val, key) => console.log(key + ': ' + val));
frequencies(aObjects).forEach((val, key) => console.log(key.value + ': ' + val));
I think this is the simplest way how to count occurrences with same value in array.
var a = [true, false, false, false];
a.filter(function(value){
return value === false;
}).length
const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
function count(arr) {
return arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})
}
console.log(count(data))
2021's version
The more elegant way is using Logical nullish assignment (x ??= y) combined with Array#reduce() with O(n) time complexity.
The main idea is still using Array#reduce() to aggregate with output as object to get the highest performance (both time and space complexity) in terms of searching & construct bunches of intermediate arrays like other answers.
const arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
const result = arr.reduce((acc, curr) => {
acc[curr] ??= {[curr]: 0};
acc[curr][curr]++;
return acc;
}, {});
console.log(Object.values(result));
Clean & Refactor code
Using Comma operator (,) syntax.
The comma operator (,) evaluates each of its operands (from left to
right) and returns the value of the last operand.
const arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
const result = arr.reduce((acc, curr) => (acc[curr] = (acc[curr] || 0) + 1, acc), {});
console.log(result);
Output
{
"2": 5,
"4": 1,
"5": 3,
"9": 1
}
If you favour a single liner.
arr.reduce(function(countMap, word) {countMap[word] = ++countMap[word] || 1;return countMap}, {});
Edit (6/12/2015):
The Explanation from the inside out.
countMap is a map that maps a word with its frequency, which we can see the anonymous function. What reduce does is apply the function with arguments as all the array elements and countMap being passed as the return value of the last function call. The last parameter ({}) is the default value of countMap for the first function call.
ES6 version should be much simplifier (another one line solution)
let arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let acc = arr.reduce((acc, val) => acc.set(val, 1 + (acc.get(val) || 0)), new Map());
console.log(acc);
// output: Map { 5 => 3, 2 => 5, 9 => 1, 4 => 1 }
A Map instead of plain Object helping us to distinguish different type of elements, or else all counting are base on strings
Edit 2020: this is a pretty old answer (nine years). Extending the native prototype will always generate discussion. Although I think the programmer is free to choose her own programming style, here's a (more modern) approach to the problem without extending Array.prototype:
{
// create array with some pseudo random values (1 - 5)
const arr = Array.from({length: 100})
.map( () => Math.floor(1 + Math.random() * 5) );
// frequencies using a reducer
const arrFrequencies = arr.reduce((acc, value) =>
({ ...acc, [value]: acc[value] + 1 || 1}), {} )
console.log(arrFrequencies);
console.log(`Value 4 occurs ${arrFrequencies[4]} times in arrFrequencies`);
// bonus: restore Array from frequencies
const arrRestored = Object.entries(arrFrequencies)
.reduce( (acc, [key, value]) => acc.concat(Array(value).fill(+key)), [] );
console.log(arrRestored.join());
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
The old (2011) answer: you could extend Array.prototype, like this:
{
Array.prototype.frequencies = function() {
var l = this.length,
result = {
all: []
};
while (l--) {
result[this[l]] = result[this[l]] ? ++result[this[l]] : 1;
}
// all pairs (label, frequencies) to an array of arrays(2)
for (var l in result) {
if (result.hasOwnProperty(l) && l !== 'all') {
result.all.push([l, result[l]]);
}
}
return result;
};
var freqs = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].frequencies();
console.log(`freqs[2]: ${freqs[2]}`); //=> 5
// or
var freqs = '1,1,2,one,one,2,2,22,three,four,five,three,three,five'
.split(',')
.frequencies();
console.log(`freqs.three: ${freqs.three}`); //=> 3
// Alternatively you can utilize Array.map:
Array.prototype.frequencies = function() {
var freqs = {
sum: 0
};
this.map(function(a) {
if (!(a in this)) {
this[a] = 1;
} else {
this[a] += 1;
}
this.sum += 1;
return a;
}, freqs);
return freqs;
}
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
Based on answer of #adamse and #pmandell (which I upvote), in ES6 you can do it in one line:
2017 edit: I use || to reduce code size and make it more readable.
var a=[7,1,7,2,2,7,3,3,3,7,,7,7,7];
alert(JSON.stringify(
a.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{})
));
It can be used to count characters:
var s="ABRACADABRA";
alert(JSON.stringify(
s.split('').reduce((a, c)=>{a[c]++?0:a[c]=1;return a},{})
));
A shorter version using reduce and tilde (~) operator.
const data = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
function freq(nums) {
return nums.reduce((acc, curr) => {
acc[curr] = -~acc[curr];
return acc;
}, {});
}
console.log(freq(data));
If you are using underscore you can go the functional route
a = ['foo', 'foo', 'bar'];
var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
_.object( _.map( _.uniq(a), function(key) { return [key, 0] })))
so your first array is
_.keys(results)
and the second array is
_.values(results)
most of this will default to native javascript functions if they are available
demo : http://jsfiddle.net/dAaUU/
So here's how I'd do it with some of the newest javascript features:
First, reduce the array to a Map of the counts:
let countMap = array.reduce(
(map, value) => {map.set(value, (map.get(value) || 0) + 1); return map},
new Map()
)
By using a Map, your starting array can contain any type of object, and the counts will be correct. Without a Map, some types of objects will give you strange counts.
See the Map docs for more info on the differences.
This could also be done with an object if all your values are symbols, numbers, or strings:
let countObject = array.reduce(
(map, value) => { map[value] = (map[value] || 0) + 1; return map },
{}
)
Or slightly fancier in a functional way without mutation, using destructuring and object spread syntax:
let countObject = array.reduce(
(value, {[value]: count = 0, ...rest}) => ({ [value]: count + 1, ...rest }),
{}
)
At this point, you can use the Map or object for your counts (and the map is directly iterable, unlike an object), or convert it to two arrays.
For the Map:
countMap.forEach((count, value) => console.log(`value: ${value}, count: ${count}`)
let values = countMap.keys()
let counts = countMap.values()
Or for the object:
Object
.entries(countObject) // convert to array of [key, valueAtKey] pairs
.forEach(([value, count]) => console.log(`value: ${value}, count: ${count}`)
let values = Object.keys(countObject)
let counts = Object.values(countObject)
var array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
function countDuplicates(obj, num){
obj[num] = (++obj[num] || 1);
return obj;
}
var answer = array.reduce(countDuplicates, {});
// answer => {2:5, 4:1, 5:3, 9:1};
If you still want two arrays, then you could use answer like this...
var uniqueNums = Object.keys(answer);
// uniqueNums => ["2", "4", "5", "9"];
var countOfNums = Object.keys(answer).map(key => answer[key]);
// countOfNums => [5, 1, 3, 1];
Or if you want uniqueNums to be numbers
var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];
Here's just something light and easy for the eyes...
function count(a,i){
var result = 0;
for(var o in a)
if(a[o] == i)
result++;
return result;
}
Edit: And since you want all the occurences...
function count(a){
var result = {};
for(var i in a){
if(result[a[i]] == undefined) result[a[i]] = 0;
result[a[i]]++;
}
return result;
}
Solution using a map with O(n) time complexity.
var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];
const countOccurrences = (arr) => {
const map = {};
for ( var i = 0; i < arr.length; i++ ) {
map[arr[i]] = ~~map[arr[i]] + 1;
}
return map;
}
Demo: http://jsfiddle.net/simevidas/bnACW/
There is a much better and easy way that we can do this using ramda.js.
Code sample here
const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
R.countBy(r=> r)(ary)
countBy documentation is at documentation
I know this question is old but I realized there are too few solutions where you get the count array as asked with a minimal code so here is mine
// The initial array we want to count occurences
var initial = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
// The count array asked for
var count = Array.from(new Set(initial)).map(val => initial.filter(v => v === val).length);
// Outputs [ 3, 5, 1, 1 ]
Beside you can get the set from that initial array with
var set = Array.from(new Set(initial));
//set = [5, 2, 9, 4]
My solution with ramda:
const testArray = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
const counfFrequency = R.compose(
R.map(R.length),
R.groupBy(R.identity),
)
counfFrequency(testArray)
Link to REPL.
Using MAP you can have 2 arrays in the output: One containing the occurrences & the other one is containing the number of occurrences.
const dataset = [2,2,4,2,6,4,7,8,5,6,7,10,10,10,15];
let values = [];
let keys = [];
var mapWithOccurences = dataset.reduce((a,c) => {
if(a.has(c)) a.set(c,a.get(c)+1);
else a.set(c,1);
return a;
}, new Map())
.forEach((value, key, map) => {
keys.push(key);
values.push(value);
});
console.log(keys)
console.log(values)
This question is more than 8 years old and many, many answers do not really take ES6 and its numerous advantages into account.
Perhaps is even more important to think about the consequences of our code for garbage collection/memory management whenever we create additional arrays, make double or triple copies of arrays or even convert arrays into objects. These are trivial observations for small applications but if scale is a long term objective then think about these, thoroughly.
If you just need a "counter" for specific data types and the starting point is an array (I assume you want therefore an ordered list and take advantage of the many properties and methods arrays offer), you can just simply iterate through array1 and populate array2 with the values and number of occurrences for these values found in array1.
As simple as that.
Example of simple class SimpleCounter (ES6) for Object Oriented Programming and Object Oriented Design
class SimpleCounter {
constructor(rawList){ // input array type
this.rawList = rawList;
this.finalList = [];
}
mapValues(){ // returns a new array
this.rawList.forEach(value => {
this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
});
this.rawList = null; // remove array1 for garbage collection
return this.finalList;
}
}
module.exports = SimpleCounter;
Using Lodash
const values = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
const frequency = _.map(_.groupBy(values), val => ({ value: val[0], frequency: val.length }));
console.log(frequency);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
To return an array which is then sortable:
let array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]
let reducedArray = array.reduce( (acc, curr, _, arr) => {
if (acc.length == 0) acc.push({item: curr, count: 1})
else if (acc.findIndex(f => f.item === curr ) === -1) acc.push({item: curr, count: 1})
else ++acc[acc.findIndex(f => f.item === curr)].count
return acc
}, []);
console.log(reducedArray.sort((a,b) => b.count - a.count ))
/*
Output:
[
{
"item": 2,
"count": 5
},
{
"item": 5,
"count": 3
},
{
"item": 9,
"count": 1
},
{
"item": 4,
"count": 1
}
]
*/
Check out the code below.
<html>
<head>
<script>
// array with values
var ar = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var Unique = []; // we'll store a list of unique values in here
var Counts = []; // we'll store the number of occurances in here
for(var i in ar)
{
var Index = ar[i];
Unique[Index] = ar[i];
if(typeof(Counts[Index])=='undefined')
Counts[Index]=1;
else
Counts[Index]++;
}
// remove empty items
Unique = Unique.filter(function(){ return true});
Counts = Counts.filter(function(){ return true});
alert(ar.join(','));
alert(Unique.join(','));
alert(Counts.join(','));
var a=[];
for(var i=0; i<Unique.length; i++)
{
a.push(Unique[i] + ':' + Counts[i] + 'x');
}
alert(a.join(', '));
</script>
</head>
<body>
</body>
</html>
function countOcurrences(arr){
return arr.reduce((aggregator, value, index, array) => {
if(!aggregator[value]){
return aggregator = {...aggregator, [value]: 1};
}else{
return aggregator = {...aggregator, [value]:++aggregator[value]};
}
}, {})
}
You can simplify this a bit by extending your arrays with a count function. It works similar to Ruby’s Array#count, if you’re familiar with it.
Array.prototype.count = function(obj){
var count = this.length;
if(typeof(obj) !== "undefined"){
var array = this.slice(0), count = 0; // clone array and reset count
for(i = 0; i < array.length; i++){
if(array[i] == obj){ count++ }
}
}
return count;
}
Usage:
let array = ['a', 'b', 'd', 'a', 'c'];
array.count('a'); // => 2
array.count('b'); // => 1
array.count('e'); // => 0
array.count(); // => 5
Gist
Edit
You can then get your first array, with each occurred item, using Array#filter:
let occurred = [];
array.filter(function(item) {
if (!occurred.includes(item)) {
occurred.push(item);
return true;
}
}); // => ["a", "b", "d", "c"]
And your second array, with the number of occurrences, using Array#count into Array#map:
occurred.map(array.count.bind(array)); // => [2, 1, 1, 1]
Alternatively, if order is irrelevant, you can just return it as a key-value pair:
let occurrences = {}
occurred.forEach(function(item) { occurrences[item] = array.count(item) });
occurences; // => {2: 5, 4: 1, 5: 3, 9: 1}

Categories

Resources