Find highest recurring duplicates in a javascript array - javascript

I have an array with several names like :
[mike,bob,john,john,rick,bob]
Can someone please tell me how is the most efficient way to find which name has been repeated the most?

Generate an object with count using Array#reduce method, later sort the property name array(get using Object.keys method) based on the count using Array#sort method and finally get the first element.
var arr = ['mike', 'bob', 'john', 'john', 'rick', 'bob'];
// generate an object which holds the count
var obj = arr.reduce(function(o, v) {
// define the property if not defined
o[v] = o[v] || 0;
// increment the count
o[v]++;
// return the object reference
return o;
// set initial value as an empty object
}, {});
// sort based on the count, descending order
// and get first
console.log(
Object.keys(obj).sort(function(a, b) {
return obj[b] - obj[a];
})[0]
)
// or using reduce, reduce into a single value
// which holds the highest value
console.log(
Object.keys(obj).reduce(function(a, b) {
return obj[b] > obj[a] ? b : a;
})
)

The standard solution to find duplicates (in O(n) time) is to walk linearly through the list and add each item to a set. Each time, before doing so, check if it is already in the set. If it is, you've found a duplicate.
names = [ 'mike', 'bob', 'john', 'john', 'rick', 'bob'];
seen = new Set();
names.forEach(function(item, index, array) {
if (seen.has(item)) {
console.log(item + " is a duplicate");
} else {
seen.add(item);
}
});
Alternately, you can sort in O(n log(n)) time, and save the extra space that was used above, by sorting and checking pair-wise as you iterate over the array:
names = [ 'mike', 'bob', 'john', 'john', 'rick', 'bob'];
names.sort().forEach(function(item, index, array) {
if ((index > 0) && (array[index - 1] == item)) {
console.log(item + " is a duplicate");
}
});

function findDup(arr){
var obj={};
for(var i of arr){
if(obj[i]==1){
console.log(i);
}
obj[i]=1;
}
}
findDup([ 'mike', 'bob', 'john', 'john', 'rick', 'bob']);

You could find with the help of map as follows
function findDuplicates() {
var name, names = ['mike', 'bob', 'john', 'john', 'rick', 'bob'];
var map = new Map();
var max = 1;
var maxRecurringString = "";
for(name of names) {
if(map.get(name) === undefined) {
map.set(name, 1);
} else {
var count = map.get(name);
count = count+1;
map.set(name, count);
if(max < count) {
max = count;
maxRecurringString = name;
}
}
}
console.log("Maximum recurring string is ", maxRecurringString, ". Max number of times :" + max);
}
findDuplicates();
This snippet prints the first string which appears maximum number of times. Say for example in the above example bob and john has appeared twice. If you want all the strings to be printed which has appeared maximum number of times you can iterate for the map whose count is the max count to print all the strings.

If you're looking for the most efficient way to do this, talking about performance, the best way is to loop over the array only once.
Array#reduce, Array#sort, Array#forEach will loop over the entire array, so if you're concerned about performance (specially working with considerable amount of data), avoiding those is the best practice
var findHighestRecurring = function(arr) {
arr.sort();
var i = arr.length;
var max = { item:"", count: 0 };
var last = { item:"", count: 0 };
var validate = function() {
if (last.count > max.count) {
max.item = last.item;
max.count = last.count;
}
}
while (i--) {
var curr = arr[i];
if (last.item !== curr) {
validate();
last.item = curr;
last.count = 0;
}
last.count++;
}
validate();
return max;
}
var sample = ["mike","bob","john","bob","john","rick","bob"];
var result = findHighestRecurring(sample);
console.log(result);

Related

Merge array of javascript objects by property key

First of all: I already found this thread, which basically is exactly what I want, but I tried my best to apply it to my needs - I couldn't.
So, I have the following javascript function:
function loadRelationData(object) {
var result = [];
var parents = []
parents = getParentObjectsByObjectID(object['ObjectID']);
var tmpFirstObjects = [];
var tmpOtherObjects = [];
$.each(parents, function (_, parent) {
var keyName = 'Übergeordnete ' + parent['ObjectType'];
var pushObject = {};
if (parent['ObjectType'] == object['ObjectType']) {
pushObject['Fieldname'] = keyName;
pushObject['Value'] = parent['Name'];
tmpFirstObjects.push(pushObject);
} else {
pushObject['Fieldname'] = keyName;
pushObject['Value'] = parent['Name'];
tmpOtherObjects.push(pushObject);
}
});
result = result.concat(tmpFirstObjects).concat(tmpOtherObjects);
return result;
}
The parents array looks like this
And my function creates this result
This might be a bit complicated, but I need to split it up like this, because I need the order.
What I want is an array with both "TEC_MapLocations" joined together like this:
[
{Fieldname: 'Übergeordnete TEC_Equipment', Value: 'E0192'},
{Fieldname: 'Übergeordnete TEC_MapLocation', Value: ['M100', 'M200']},
{Fieldname: 'Übergeordnete TEC_FunctionalLocation', Value: 'FL456'}
]
Any ideas on how to alter my code to achieve the desired result right away or how to merge the results array?
edit: I used Joseph's solution and used the following (quick and dirty) sort function to get back my desired sorting:
output.sort(function (a, b) {
if (a.ObjectType == object.ObjectType) {
return -1
} else {
return 1
}
});
What you'd want to do first is build a hash with Fieldname as key, and an array as value. Then you'd want to use reduce to add the values into the hash and array. Then you can transform it into an array using Object.keys and map.
var input = [
{Name: 'M100', ObjectID: 1, ObjectType: 'TEC_MapLocation'},
{Name: 'M200', ObjectID: 2, ObjectType: 'TEC_MapLocation'},
{Name: 'FL456', ObjectID: 4, ObjectType: 'TEC_FunctionalLocation'},
{Name: 'E0192', ObjectID: 5, ObjectType: 'TEC_Equipment'}
];
var hash = input.reduce(function(carry, item){
// Create the name
var name = 'Übergeordnete ' + item.ObjectType;
// If array with name doesn't exist, create it
if(!carry[name]) carry[name] = [];
// If item isn't in the array, add it.
if(!~carry[name].indexOf(item.Name)) carry[name].push(item.Name);
return carry;
}, {});
// Convert the hash into an array
var output = Object.keys(hash).map(function(key, index, array){
return { Fieldname: key, Value: hash[key] }
});
document.write(JSON.stringify(output));
Try this:
function joinObjects( array ) {
// Start with empty array
var ret = new Array();
// Iterate array
for ( var i = 0; i < array.length; i++ ) {
// Search by fieldname
var match = false;
var j;
for ( j = 0; j < ret.length; j++ ) {
if ( array[i].Fieldname == ret[j].Fieldname ) { match = true; break; }
}
// If not exists
if ( !match ) {
// Intert object
ret.push({
Fieldname: array[i].Fieldname,
Value: new Array()
});
}
// Insert value
ret[j].Value.push( array[i].Value );
}
// Return new array
return ret;
}
http://jsfiddle.net/6entfv4x/

Find object having maximum value for the `id` property in an array of objects

In my array of objects, I want to find the object with the highest value for the id property.
Here is my array:
myArray = [
{
'id': '73',
'foo': 'bar'
},
{
'id': '45',
'foo': 'bar'
},
// …
];
Generally, I use $.grep to find values in an array, like this:
var result = $.grep(myArray, function (e) {
return e.id == 73;
});
But in this case I need to provide a specific id value for the object I want to select.
The question states that he wants to find the object with the greatest id, not just the greatest id...
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var max = myArray.reduce(function(prev, current) {
if (+current.id > +prev.id) {
return current;
} else {
return prev;
}
});
// max == {'id':'73','foo':'bar'}
const students = [
{ id: 100, name: 'Abolfazl', family: 'Roshanzamir' },
{ id: 2, name: 'Andy', family: 'Madadian' },
{ id: 1500, name: 'Kouros', family: 'Shahmir' }
]
If you want to find the object with max Id :
const item = students.reduce((prev, current) => (+prev.id > +current.id) ? prev : current)
// it returns { id: 1500, name: 'Kouros', family: 'Shahmir' }
If you want to find the object with min Id :
const item = students.reduce((prev, current) => (+prev.id < +current.id) ? prev : current)
// it returns {id: 2, name: "Andy", family: "Madadian"}
If you wnat to find the max Id :
const max = Math.max.apply(null, students.map(item => item.id));
// it returns 1500
If you want to find the min Id :
const min = Math.min.apply(null, students.map(item => item.id));
// it returns 2
Use the map() method of the array. Using map you can provide a function that iterates over every element in the array. In that function, you can work out the object with the highest id. For example:
myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var maxid = 0;
myArray.map(function(obj){
if (obj.id > maxid) maxid = obj.id;
});
This will give you the max id of the objects in the array.
Then you can use grep to get the related object:
var maxObj = $.grep(myArray, function(e){ return e.id == maxid; });
Alternatively, if you just want the object with the max id, you can do this:
var maxid = 0;
var maxobj;
myArray.map(function(obj){
if (obj.id > maxid) maxobj = obj;
});
//maxobj stores the object with the max id.
var max = 0;
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}]
var maxEle = myArray.map(function(ele){ if(ele.id>max){ max=ele} });
map is a function which iterates through array elements and performs specific operation.
let id = items.reduce((maxId, item) => Math.max(maxId, item.id), 0);
or
let id = Math.max(...items.map(item => item.id).concat(0)); // concat(0) for empty array
// slimmer and sleeker ;)
let id = Math.max(...items.map(item => item.id), 0);
This way is more practical, because in the case of an empty array, it returns 0, unlike
Math.max.apply(null, [].map(item => item.id)) // -Infinity
and if you want to get "autoincrement", you can just add 1 regardless of whether the array is empty or not
// starts at 1 if our array is empty
autoincrement = items.reduce((maxId, item) => Math.max(maxId, item.id), 0) + 1;
UPD: Code with map is shorter but with reduce is faster, which is felt with large arrays
let items = Array(100000).fill()
.map((el, _, arr) => ({id: ~~(Math.random() * arr.length), name: 'Summer'}));
const n = 100;
console.time('reduce test');
for (let i = 1; i < n; ++i) {
let id = items.reduce((maxId, item) => Math.max(maxId, item.id), 0);
}
console.timeEnd('reduce test');
console.time('map test');
for (let i = 1; i < n; ++i) {
let id = Math.max(items.map(item => item.id).concat(0));
}
console.timeEnd('map test');
console.time('map spread test');
for (let i = 1; i < n; ++i) {
let id = Math.max(...items.map(item => item.id), 0);
}
console.timeEnd('map spread test');
reduce test: 163.373046875ms
map test: 1282.745849609375ms
map spread test: 242.4111328125ms
If we create an even larger array, spread map will shutdown
let items = Array(200000).fill()
.map((el, _, arr) => ({id: ~~(Math.random() * arr.length), name: 'Summer'}));
reduce test: 312.43896484375ms
map test: 2941.87109375ms
Uncaught RangeError: Maximum call stack size exceeded
at :15:32
function reduceBy(reducer, acc) {
return function(by, arr) {
return arr[arr.reduce(function(acc, v, i) {
var b = by(v);
return reducer(acc[0], b) ? [b, i] : acc;
}, acc || [by(arr[0]), 0])[1]];
};
}
var maximumBy = reduceBy(function(a,b){return a<b;});
var myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
console.log(maximumBy(function(x){
return parseInt(x.id,10)
}, myArray)); // {'id':'73','foo':'bar'}
a shorten version using reduce()
myArray.reduce((max, cur)=>(max.likes>cur.likes?max:cur))

Count unique elements in array without sorting

In JavaScript the following will find the number of elements in the array. Assuming there to be a minimum of one element in the array
arr = ["jam", "beef", "cream", "jam"]
arr.sort();
var count = 1;
var results = "";
for (var i = 0; i < arr.length; i++)
{
if (arr[i] == arr[i+1])
{
count +=1;
}
else
{
results += arr[i] + " --> " + count + " times\n" ;
count=1;
}
}
Is it possible to do this without using sort() or without mutating the array in any way? I would imagine that the array would have to be re-created and then sort could be done on the newly created array, but I want to know what's the best way without sorting.
And yes, I'm an artist, not a programmer, your honour.
The fast way to do this is with a new Set() object.
Sets are awesome and we should use them more often. They are fast, and supported by Chrome, Firefox, Microsoft Edge, and node.js.
— What is faster Set or Object? by Andrei Kashcha
The items in a Set will always be unique, as it only keeps one copy of each value you put in. Here's a function that uses this property:
function countUnique(iterable) {
return new Set(iterable).size;
}
console.log(countUnique('banana')); //=> 3
console.log(countUnique([5,6,5,6])); //=> 2
console.log(countUnique([window, document, window])); //=> 2
This can be used to count the items in any iterable (including an Array, String, TypedArray, and arguments object).
A quick way to do this is to copy the unique elements into an Object.
var counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = 1 + (counts[arr[i]] || 0);
}
When this loop is complete the counts object will have the count of each distinct element of the array.
Why not something like:
var arr = ["jam", "beef", "cream", "jam"]
var uniqs = arr.reduce((acc, val) => {
acc[val] = acc[val] === undefined ? 1 : acc[val] += 1;
return acc;
}, {});
console.log(uniqs)
Pure Javascript, runs in O(n). Doesn't consume much space either unless your number of unique values equals number of elements (all the elements are unique).
Same as this solution, but less code.
let counts = {};
arr.forEach(el => counts[el] = 1 + (counts[el] || 0))
This expression gives you all the unique elements in the array without mutating it:
arr.filter(function(v,i) { return i==arr.lastIndexOf(v); })
You can chain it with this expression to build your string of results without sorting:
.forEach(function(v) {
results+=v+" --> " + arr.filter(function(w){return w==v;}).length + " times\n";
});
In the first case the filter takes only includes the last of each specific element; in the second case the filter includes all the elements of that type, and .length gives the count.
This answer is for Beginners. Try this method you can solve this problem easily. You can find a full lesson for reduce, filter, map functions from This link.
const user = [1, 2, 2, 4, 8, 3, 3, 6, 5, 4, 8, 8];
const output = user.reduce(function (acc, curr) {
if (acc[curr]) {
acc[curr] = ++acc[curr];
} else {
acc[curr] = 1;
}
return acc;
}, {});
console.log(output);
function reomveDuplicates(array){
var newarray = array.filter( (value, key)=>{
return array.indexOf(value) == key
});
console.log("newarray", newarray);
}
reomveDuplicates([1,2,5,2,1,8]);
Using hash Map with the time complexity O(n)
function reomveDuplicates(array){
var obj ={};
let res=[];
for( arg of array){
obj[arg] = true;
}
console.log(Object.keys(obj));
for(key in obj){
res.push(Number(key)); // Only if you want in Number
}
console.log(res);
}
reomveDuplicates([1,2,5,2,1,8]);
In a modern, extensible and easy-to-read approach, here's one using iter-ops library:
import {pipe, distinct, count} from 'iter-ops';
const arr = ['jam', 'beef', 'cream', 'jam'];
const count = pipe(arr, distinct(), count()).first;
console.log(count); //=> 3
function check(arr) {
var count = 0;
for (var ele of arr) {
if (typeof arr[ele] !== typeof (arr[ele+1])) {
count++;
} else {
("I don't know");
}
}
return count;
}

Check if an array contains an object with a certain property value in JavaScript?

If I have something like
[Object(id:03235252, name:"streetAddress"), Object(id:32624666, name:"zipCode")...]
How can I remove an object from that array that has name set to "zipCode"?
If you need to modify the existing Array, you should use splice().
for (var i = array.length - 1; i > -1; i--) {
if (array[i].name === "zipCode")
array.splice(i, 1);
}
Notice that I'm looping in reverse. This is in order to deal with the fact that when you do a .splice(i, 1), the array will be reindexed.
If we did a forward loop, we would also need to adjust i whenever we do a .splice() in order to avoid skipping an index.
arr = arr.filter(function (item) {
return (item.name !== 'zipCode');
});
Updated suggestion
Updated this answer due to doing prototypes on arrays are bad prac so to get people who use the suggestion to write better code here is a better option:
const myArr = [
{
name: "lars",
age: 25
}, {
name: "hugo",
age: 28
}, {
name: "bent",
age: 24
}, {
name: "jimmy",
age: 22
}
];
const findAndRemove = (array, prop, value) => {
return array.filter((item) => item[prop] !== value);
}
const newArr = findAndRemove(myArr, 'name', 'jimmy')
console.log(newArr)
// Could also be simply written like this:
const otherArr = myArr.filter(item => item.name !== 'jimmy')
New code can be found and tested here
Old suggestion
This can also be done with a prototype on the array
Array.prototype.containsByProp = function(propName, value){
for (var i = this.length - 1; i > -1; i--) {
var propObj = this[i];
if(propObj[propName] === value) {
return true;
}
}
return false;
}
var myArr = [
{
name: "lars",
age: 25
}, {
name: "hugo",
age: 28
}, {
name: "bent",
age: 24
}, {
name: "jimmy",
age: 22
}
];
console.log(myArr.containsByProp("name", "brent")); // Returns false
console.log(myArr.containsByProp("name", "bent")); // Returns true
Code can also be found and tested here
var i = array.length;
while(i-- > 0) {
if (array[i].name === "zipCode")
array.splice(i, 1);
}
Loop through the array backwards (so you won't have to skip indexes when splicing)
Check each item's name if it's "zipCode"
If it is, splice it off using yourArray.splice(index,1);
Then either:
continue if there is a possibility of having more than one name having the value "zipCode"
break the loop
This may be a detailed and easy solution.
//plain array
var arr = ['a', 'b', 'c'];
var check = arr.includes('a');
console.log(check); //returns true
if (check)
{
// value exists in array
//write some codes
}
// array with objects
var arr = [
{x:'a', y:'b'},
{x:'p', y:'q'}
];
// if you want to check if x:'p' exists in arr
var check = arr.filter(function (elm){
if (elm.x == 'p')
{
return elm; // returns length = 1 (object exists in array)
}
});
// or y:'q' exists in arr
var check = arr.filter(function (elm){
if (elm.y == 'q')
{
return elm; // returns length = 1 (object exists in array)
}
});
// if you want to check, if the entire object {x:'p', y:'q'} exists in arr
var check = arr.filter(function (elm){
if (elm.x == 'p' && elm.y == 'q')
{
return elm; // returns length = 1 (object exists in array)
}
});
// in all cases
console.log(check.length); // returns 1
if (check.length > 0)
{
// returns true
// object exists in array
//write some codes
}

Shuffling array properties in JavaScript

I have a data dictionary like this:
var data = {
'text1': 1,
'text2': 2,
'text3': 3,
...
'text20': 20
];
I need to pick a random selection of those keys and then shuffle it's values. In the example, it should write something like this:
> console.log(choose(data, 5));
[ { key: 'text15', value: 8 },
{ key: 'text6', value: 3 },
{ key: 'text3', value: 15 },
{ key: 'text19', value: 6 },
{ key: 'text8', value: 19 } ]
For now I'm extracting the keys into another array and sorting by Math.random() but I'm stuck at swaping the values because no key should have the same value it initially had.
How would you swap key/values here?
Thanks
I put together a possible solution using underscore.js to simplify traversing the object and arrays in a cross browser manner:
var data = {
text1: 1,
text2: 2,
text3: 3,
text4: 4,
text5: 5,
text6: 6,
text7: 7,
text8: 8,
text9: 9,
text10: 10
};
function choose(data, num)
{
var keys = _.sortBy(
_.keys(data),
function(k)
{
return (Math.random() * 3) - 1;
}
),
results = [],
k1, k2;
if (num > keys.length) {
throw new Error('Impossible to retrieve more values than exist');
}
while (results.length < num) {
k1 = k2 || keys.pop();
k2 = keys.pop();
results.push({key:k1, value: data[k2]});
}
return results;
}
console.log(choose(data, 5));
This isn't necessarily an optimal approach but it seems to meet your requirements. I first grab all of the keys and sort them randomly. I then loop through the random keys creating a new object with one key and the following keys value. That way you'll always end up with a different value associated with each key. If you need it to work when the value of num passed in to the function == the number of keys in the data then you'll have to add a little more code - I'll leave that as an exercise for the reader :)
You can have a play with this code on jsfiddle:
http://jsfiddle.net/zVyQW/1/
You could do this:
collect names and corresponding values in two arrays names and values
shuffle both arrays independently of each other
take the first n items of both arrays and combine them
Here’s an example implementation:
Array.prototype.shuffle = function() {
for (var i=this.length-1, j, tmp; i>0; i--) {
j = Math.round(Math.random()*i);
tmp = this[i], this[i] = this[j], this[j] = tmp;
}
return this;
};
function choose(data, number) {
var names = [], values = [], pick = [];
for (var name in data) {
if (data.hasOwnProperty(name)) {
names.push(name);
values.push(data[name]);
}
}
names = names.shuffle(), values = values.shuffle();
for (var i=Math.min(number >>> 0, names.length-1); i>=0; i--) {
pick.push({key: names[i], value: values[i]});
}
return pick;
}
Been a while since this was answered, but I was working on shuffling and found the following to be by far the fastest implementation with an evenly random distribution.
It's fast because it only makes one call to Math.random on each iteration, all the rest is done by property access. It doesn't modify the array, just reassigns values.
function shuffle(a) {
var t, j, i=a.length, rand=Math.random;
// For each element in the array, swap it with a random
// element (which might be itself)
while (i--) {
k = rand()*(i+1)|0;
t = a[k];
a[k]=a[i];
a[i]=t;
}
return a;
}
It uses a combination of three functions (including the Array shuffle prototype method).
Here is the complete code:
var obj = {
"red":"RED",
"blue":"BLUE",
"green":"GREEN",
"yellow":"YELLOW",
"purple":"PURPLE"
};
Array.prototype.shuffle = function(){
for (var i = 0; i < this.length; i++){
var a = this[i];
var b = Math.floor(Math.random() * this.length);
this[i] = this[b];
this[b] = a;
}
}
obj = shuffleProperties(obj); // run shuffle
function shuffleProperties(obj) {
var new_obj = {};
var keys = getKeys(obj);
keys.shuffle();
for (var key in keys){
if (key == "shuffle") continue; // skip our prototype method
new_obj[keys[key]] = obj[keys[key]];
}
return new_obj;
}
function getKeys(obj){
var arr = new Array();
for (var key in obj)
arr.push(key);
return arr;
}
for(key in obj){
alert(key);
}
Check all post,
Best Regards.
Use an implementation of random that randomizes a discrete set of values, such as Math.rand seen here. For each index, randomize Math.rand(index, length-1) to get a list of random indexes, the location off all indices will change.

Categories

Resources