I wanted to create a function, that counts all unique Items in an array, but somehow I do not get any output.
This is my array!
let arr = ["hi", "hello", "hi"];
And this is the code I wrote so far:
function countUnique(arr) {
var counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = 1 + (counts[arr[i]] || 0);
}
countUnique(arr);
}
console.log(countUnique(arr));
Your are counting values correctly, however then you are calling this method recursively countUnique(arr); and it results an error of call stack exceeded.
So just remove recursive call of method countUnique(arr); and return counted value counts:
function countUnique(arr) {
var counts = {};
for (var i = 0; i < arr.length; i++) {
counts[arr[i]] = 1 + (counts[arr[i]] || 0);
}
return counts;
}
let arr = ["hi", "hello", "hi"];
console.log(countUnique(arr));
JavaScript engine limits the maximal recursion depth. We can rely on it being 10000, some engines allow more.
You could take a Set and return the size.
const countUnique = array => new Set(array).size;
console.log(countUnique(["hi", "hello", "hi"]));
let arr = ["hi", "hello", "hi"];
function countUnique(arr) {
var counts = {};
for (var i = 0; i < arr.length; i++) {
if(arr[i] in counts) {
counts[arr[i]]++;
} else {
counts[arr[i]] = 1;
}
}
return Object.keys(counts).length;
}
console.log(countUnique(arr));
I am trying to compare two arrays and check if they are the same. According to the logic below the function should return DRAW as the arrays I am comparing to are exactly the same. It returns undefined instead. I cannot figure it out why it doesn't return draw. If I change the && to || it returns draw so I assume there is an issue with the logical operator.
function isSolved(board) {
// TODO: Check if the board is solved!
var arraya = [1,1,1];
var arrayb = [2,2,2];
for (var i = 0; i < board.length; i++){
for (var j = 0; j < board[i].length; j++) {
if (board[i][j] === 0) {
return false;
} else if (
(JSON.stringify(board[i]) === JSON.stringify(arraya))
&& (JSON.stringify(board[i]) ===JSON.stringify(arrayb))) {
return "draw"
}
}
}
}
console.log(
isSolved([
[1,1,1],
[1,2,2],
[2,2,2]
])
);
You can use JSON.stringify like this:
var arraya = [1,1,1];
var arrayb = [2,2,2];
function isSolved(a, b) {
return JSON.stringify(a) === JSON.stringify(b) ? "draw" : false;
};
var input = [[1,1,1], [1,2,2], [2,2,2]];
for (var item of input) {
console.log(isSolved(item, arraya));
console.log(isSolved(item, arrayb));
console.log("=====");
}
I am trying to solve a freeCodeCamp exercise and have gotten stuck. The goal of the exercise is this: Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument). Each property and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.
So what I did, was to make an array of the key pairs of the collection, and another array with the key pairs of the source. The I nested for-loops in order to find matching keys, and if those keys are found, then compare the properties.
But somehow, my code returns no matches.
var collection = [{
first: "Romeo",
last: "Montague"
}, {
first: "Mercutio",
last: null
}, {
first: "Tybalt",
last: "Capulet"
}];
var source = {
last: "Capulet"
};
var collectionKeys = [];
for (var i = 0; i < collection.length; i++) {
collectionKeys.push(Object.keys(collection[i]));
}
var sourceKeys = Object.keys(source);
//for every key pair
for (var t = 0; t < collectionKeys.length; t++) {
//for every key in key pair
for (var x = 0; x < collectionKeys[t].length; x++) {
//for every key in search
for (var y = 0; y < sourceKeys.length; y++) {
//see if a key matches
if (sourceKeys[y] == collectionKeys[t][x]) {
//see if the value matches
if (collection[collectionKeys[t][x]] == source[sourceKeys[y]]) {
console.log(collection[t]);
} else {
console.log("value not found");
}
} else {
console.log("key not found");
}
}
}
}
Can anybody point out what I'm doing wrong?
I've also created a JSfiddle if you want to tinker.
I was also stuck on this for a good hour, when I stumbled upon a couple resources to assist.
I found that rather than the mess of nested for loops, I could use the built in looping methods to greatly simplify my code.
here is where I found my explanation:
https://github.com/Rafase282/My-FreeCodeCamp-Code/wiki/Bonfire-Where-art-thou
function where(collection, source) {
var arr = [];
var keys = Object.keys(source);
// Filter array and remove the ones that do not have the keys from source.
arr = collection.filter(function(obj) {
//Use the Array method every() instead of a for loop to check for every key from source.
return keys.every(function(key) {
// Check if the object has the property and the same value.
return obj.hasOwnProperty(key) && obj[key] === source[key];
});
});
return arr;
}
be more explicit in your declarations - helps to read the code easier:
var sourceKeys = Object.keys(source),
i = 0,
j = 0,
collectionLength = collection.length,
sourceKeysLength = sourceKeys.length;
while (i < collectionLength) {
j = 0;
while (j < sourceKeysLength) {
if (sourceKeys[j] in collection[i] && source[sourceKeys[j]] === collection[i][sourceKeys[j]]) {
console.log('found one!');
}
j++;
}
i++;
}
https://jsfiddle.net/fullcrimp/1cyy8z64/
Some insight here with clear understanding and less loops.
some new javascript function like some, filter, map are really handy to make code tidier as well.
function whatIsInAName(collection, source) {
// What's in a name?
var arr = [];
// Only change code below this line
collection.some(function(obj){
var sk = Object.keys(source); //keys of source object
var sv = Object.values(source); //values of source object
var temp = 0;
for(i=0;i<sk.length;i++){ // run until the number of source properties length is reached.
if(obj.hasOwnProperty(sk[i]) && obj[sk[i]] === sv[i]){ // if it has the same properties and value as parent object from collection
temp++; //temp value is increased to track if it has matched all the properties in an object
}
}
if(sk.length === temp){ //if the number of iteration has matched the temp value
arr.push(obj);
temp = 0; // make temp zero so as to count for the another object from collection
}
})
// Only change code above this line
return arr;
}
var collection = [{
first: "Romeo",
last: "Montague"
}, {
first: "Mercutio",
last: null
}, {
first: "Tybalt",
last: "Capulet"
}];
var source = {
last: "Capulet"
};
var collectionKeys = [];
for (var i = 0; i < collection.length; i++) {
collectionKeys.push(Object.keys(collection[i]));
}
var sourceKeys = Object.keys(source);
//for every key pair
for (var t = 0; t < collectionKeys.length; t++) {
//for every key in key pair
for (var x = 0; x < collectionKeys[t].length; x++) {
//for every key in search
for (var y = 0; y < sourceKeys.length; y++) {
//see if a key matches
if (sourceKeys[y] == collectionKeys[t][x]) {
if (collection[t][collectionKeys[t][x]] == source[sourceKeys[y]]) {
alert(collection[t].first+ " "+collection[t].last);
} else {
console.log("value not found");
}
} else {
console.log("key not found");
}
}
}
}
Change collection[collectionKeys[t][x]] to collection[t][collectionKeys[t][x]]..collection[collectionKeys[t][x]] gives undefined in console.
This is what I came to on the same problem.
function whereAreYou(collection, source) {
// What's in a name?
// Only change code below this line
var arr = [];
var validObject;
// check each object
for (var each_object in collection ){
validObject = true;
for (var key in source ){
if ( collection[each_object].hasOwnProperty(key)){
if ( collection[each_object][key] != source[key]){
// if no valid key
validObject = false;
}
} else {
// if no valid value
validObject = false;
}
}
// otherwise, give it a green light
if(validObject){
arr.push(collection[each_object]);
}
}
return arr;
}
function whatIsInAName(collection, source) {
const keyCount = Object.keys(source).length;
return collection.filter((item) => {
return Object.entries(item).reduce((acc, [key, value], _, arr) => {
if (keyCount > arr.length) {
acc = false;
} else if (keyCount === arr.length && !source[key]) {
acc = false;
} else if (source[key] && source[key] !== value) {
acc = false;
}
return acc;
}, true)
})
}
This question already has answers here:
In Javascript, how do I check if an array has duplicate values?
(9 answers)
Closed 10 months ago.
I wanted to write a javascript function which checks if array contains duplicate values or not.
I have written the following code but its giving answer as "true" always.
Can anybody please tell me what am I missing.
function checkIfArrayIsUnique(myArray)
{
for (var i = 0; i < myArray.length; i++)
{
for (var j = 0; j < myArray.length; j++)
{
if (i != j)
{
if (myArray[i] == myArray[j])
{
return true; // means there are duplicate values
}
}
}
}
return false; // means there are no duplicate values.
}
An easy solution, if you've got ES6, uses Set:
function checkIfArrayIsUnique(myArray) {
return myArray.length === new Set(myArray).size;
}
let uniqueArray = [1, 2, 3, 4, 5];
console.log(`${uniqueArray} is unique : ${checkIfArrayIsUnique(uniqueArray)}`);
let nonUniqueArray = [1, 1, 2, 3, 4, 5];
console.log(`${nonUniqueArray} is unique : ${checkIfArrayIsUnique(nonUniqueArray)}`);
let arr = [11,22,11,22];
let hasDuplicate = arr.some((val, i) => arr.indexOf(val) !== i);
// hasDuplicate = true
True -> array has duplicates
False -> uniqe array
This should work with only one loop:
function checkIfArrayIsUnique(arr) {
var map = {}, i, size;
for (i = 0, size = arr.length; i < size; i++){
if (map[arr[i]]){
return false;
}
map[arr[i]] = true;
}
return true;
}
You got the return values the wrong way round:
As soon as you find two values that are equal, you can conclude that the array is not unique and return false.
At the very end, after you've checked all the pairs, you can return true.
If you do this a lot, and the arrays are large, you might want to investigate the possibility of sorting the array and then only comparing adjacent elements. This will have better asymptotic complexity than your current method.
Assuming you're targeting browsers that aren't IE8,
this would work as well:
function checkIfArrayIsUnique(myArray)
{
for (var i = 0; i < myArray.length; i++)
{
if (myArray.indexOf(myArray[i]) !== myArray.lastIndexOf(myArray[i])) {
return false;
}
}
return true; // this means not unique
}
Here's an O(n) solution:
function hasDupes(arr) {
/* temporary object */
var uniqOb = {};
/* create object attribute with name=value in array, this will not keep dupes*/
for (var i in arr)
uniqOb[arr[i]] = "";
/* if object's attributes match array, then no dupes! */
if (arr.length == Object.keys(uniqOb).length)
alert('NO dupes');
else
alert('HAS dupes');
}
var arr = ["1/1/2016", "1/1/2016", "2/1/2016"];
hasDupes(arr);
https://jsfiddle.net/7kkgy1j3/
Another solution:
Array.prototype.checkIfArrayIsUnique = function() {
this.sort();
for ( var i = 1; i < this.length; i++ ){
if(this[i-1] == this[i])
return false;
}
return true;
}
function hasNoDuplicates(arr) {
return arr.every(num => arr.indexOf(num) === arr.lastIndexOf(num));
}
hasNoDuplicates accepts an array and returns true if there are no duplicate values. If there are any duplicates, the function returns false.
Without a for loop, only using Map().
You can also return the duplicates.
(function(a){
let map = new Map();
a.forEach(e => {
if(map.has(e)) {
let count = map.get(e);
console.log(count)
map.set(e, count + 1);
} else {
map.set(e, 1);
}
});
let hasDup = false;
let dups = [];
map.forEach((value, key) => {
if(value > 1) {
hasDup = true;
dups.push(key);
}
});
console.log(dups);
return hasDup;
})([2,4,6,2,1,4]);
Late answer but can be helpful
function areThereDuplicates(args) {
let count = {};
for(let i = 0; i < args.length; i++){
count[args[i]] = 1 + (count[args[i]] || 0);
}
let found = Object.keys(count).filter(function(key) {
return count[key] > 1;
});
return found.length ? true : false;
}
areThereDuplicates([1,2,5]);
The code given in the question can be better written as follows
function checkIfArrayIsUnique(myArray)
{
for (var i = 0; i < myArray.length; i++)
{
for (var j = i+1; j < myArray.length; j++)
{
if (myArray[i] == myArray[j])
{
return true; // means there are duplicate values
}
}
}
return false; // means there are no duplicate values.
}
Returns the duplicate item in array and creates a new array with no duplicates:
var a = ["hello", "hi", "hi", "juice", "juice", "test"];
var b = ["ding", "dong", "hi", "juice", "juice", "test"];
var c = a.concat(b);
var dupClearArr = [];
function dupArray(arr) {
for (i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) != i && arr.indexOf(arr[i]) != -1) {
console.log('duplicate item ' + arr[i]);
} else {
dupClearArr.push(arr[i])
}
}
console.log('actual array \n' + arr + ' \nno duplicate items array \n' + dupClearArr)
}
dupArray(c);
const containsMatches = (a1, a2) => a1.some((v) => a2.includes(v));
If your array nests other arrays/objects, using the Set approach may not be what you want since comparing two objects compares their references. If you want to check that their contained values are equal, something else is needed. Here are a couple different approaches.
Approach 1: Map using JSON.stringify for keys
If you want to consider objects with the same contained values as equal, here's one simple way to do it using a Map object. It uses JSON.stringify to make a unique id for each element in the array.
I believe the runtime of this would be O(n * m) on arrays, assuming JSON.stringify serializes in linear time. n is the length of the outer array, m is size of the arrays. If the objects get very large, however, this may slow down since the keys will be very long. Not a very space-efficient implementation, but it is simple and works for many data types.
function checkArrayDupeFree(myArray, idFunc) {
const dupeMap = new Map();
for (const el of myArray) {
const id = idFunc(el);
if (dupeMap.has(id))
return false;
dupeMap.set(id, el);
}
return true;
}
const notUnique = [ [1, 2], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(notUnique)} has no duplicates? ${checkArrayDupeFree(notUnique, JSON.stringify)}`);
const unique = [ [2, 1], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(unique)} has no duplicates? ${checkArrayDupeFree(unique, JSON.stringify)}`);
Of course, you could also write your own id-generator function, though I'm not sure you can do much better than JSON.stringify.
Approach 2: Custom HashMap, Hashcode, and Equality implementations
If you have a lot of big arrays, it may be better performance-wise to implement your own hash/equality functions and use a Map as a HashMap.
In the following implementation, we hash the array. If there is a collision, map a key to an array of collided values, and check to see if any of the array values match according to the equality function.
The downside of this approach is that you may have to consider a wide range of types for which to make hashcode/equality functions, depending on what's in the array.
function checkArrayDupeFreeWHashes(myArray, hashFunc, eqFunc) {
const hashMap = new Map();
for (const el of myArray) {
const hash = hashFunc(el);
const hit = hashMap.get(hash);
if (hit == null)
hashMap.set(hash, [el]);
else if (hit.some(v => eqFunc(v, el)))
return false;
else
hit.push(el);
}
return true;
}
Here's a demo of the custom HashMap in action. I implemented a hashing function and an equality function for arrays of arrays.
function checkArrayDupeFreeWHashes(myArray, hashFunc, eqFunc) {
const hashMap = new Map();
for (const el of myArray) {
const hash = hashFunc(el);
const hit = hashMap.get(hash);
if (hit == null)
hashMap.set(hash, [el]);
else if (hit.some(v => eqFunc(v, el)))
return false;
else
hit.push(el);
}
return true;
}
function arrayHasher(arr) {
let hash = 19;
for (let i = 0; i < arr.length; i++) {
const el = arr[i];
const toHash = Array.isArray(el)
? arrayHasher(el)
: el * 23;
hash = hash * 31 + toHash;
}
return hash;
}
function arrayEq(a, b) {
if (a.length != b.length)
return false;
for (let i = 0; i < a.length; i++) {
if ((Array.isArray(a) || Array.isArray(b)) && !arrayEq(a[i], b[i]))
return false;
else if (a[i] !== b[i])
return false;
}
return true;
}
const notUnique = [ [1, 2], [1, 3], [1, 2] ];
const unique = [ [2, 1], [1, 3], [1, 2] ];
console.log(`${JSON.stringify(notUnique)} has no duplicates? ${checkArrayDupeFreeWHashes(notUnique, arrayHasher, arrayEq)}`);
console.log(`${JSON.stringify(unique)} has no duplicates? ${checkArrayDupeFreeWHashes(unique, arrayHasher, arrayEq)}`);
function checkIfArrayIsUnique(myArray)
{
isUnique=true
for (var i = 0; i < myArray.length; i++)
{
for (var j = 0; j < myArray.length; j++)
{
if (i != j)
{
if (myArray[i] == myArray[j])
{
isUnique=false
}
}
}
}
return isUnique;
}
This assume that the array is unique at the start.
If find two equals values, then change to false
i think this is the simple way
$(document).ready(function() {
var arr = [1,2,3,9,6,5,6];
console.log( "result =>"+ if_duplicate_value (arr));
});
function if_duplicate_value (arr){
for(i=0;i<arr.length-1;i++){
for(j=i+1;j<arr.length;j++){
if(arr[i]==arr[j]){
return true;
}
}
}
return false;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
var c=[2,2,3,3,5,5,4,4,8,8];
for(var i=0; i<b.length; i++){
for(var j=i+1; j<b.length; j++){
if(c[i]==c[j]){
console.log(c[j]);
}
}
}
I would like a function that compares to arrays of javascript strings, and saving the values that didnt match in to a new array. At the moment im using a nested jquery foreach. But i think there are better ways than this?
$.each(imagesInUploadsFolder, function(i, outervalue){
$.each(imagesInDatabaseTable, function(i, innervalue){
if(outervalue == innervalue){
//match in both arrays...
}
});
});
How about this:
arr1.forEach( function ( elem ) {
if ( arr2.indexOf( elem ) > -1 ) {
// match...
}
});
where arr1 and arr2 are your two arrays...
(Btw, ES5 shim for IE8, of course...)
Here's a way using a JSON object and no jQuery, although the $.inArray() should work fine:
var imagesInUploadsFolder = [
'/path/to/img1.png',
'/path/to/img2.png',
'/path/to/img3.png'
];
var imagesInDatabaseTable = [
'/path/to/img1.jpg',
'/path/to/img2.png',
'/path/to/img4.png'
];
var database_json = JSON.stringify(imagesInDatabaseTable);
for (var i = 0; i < imagesInUploadsFolder.length; i++) {
console.log(imagesInUploadsFolder[i] + ' in ' + database_json);
if (database_json.indexOf(imagesInUploadsFolder[i]) > -1) {
console.log('In database: ' + imagesInUploadsFolder[i]);
} else {
console.log('Not in database: ' + imagesInUploadsFolder[i]);
}
}
http://jsfiddle.net/7nJPW/1/
EDIT
Actually, the JSON method isn't needed (?):
for (var i = 0; i < imagesInUploadsFolder.length; i++) {
console.log(imagesInUploadsFolder[i] + ' in ' + imagesInDatabaseTable);
if (imagesInDatabaseTable.indexOf(imagesInUploadsFolder[i]) > -1) {
console.log('In database: ' + imagesInUploadsFolder[i]);
} else {
console.log('Not in database: ' + imagesInUploadsFolder[i]);
}
}
http://jsfiddle.net/7nJPW/2/
Why not use foreach of pure javascript?
for (var i = 0; i < innervalue.length; i++) {
for (var j = 0; j < outervalue.length; j++){
if (innervalue[i] === outervalue[j])
// match
}
}
It is the most easier way i can think of right now :)
$.each(imagesInUploadsFolder, function(i, outervalue){
if($.inArray(imagesInDatabaseTable,outervalue)>-1){
//my operation
}
}
FYI: Actually inArray returns index of innermatch else -1. Just incase you need it.
Whether you use jQuery or for loops, straight-out comparison will be O(n2), since you'll need to compare each element of one array with every element of another array.
If the objects are comparable, you can sort the items using a suitable comparison function, then loop over the two arrays simultaneously, examining if one element is less than the other. If you're familiar with merge-sort, this is very similar to the merge step. Assuming the comparison function is O(1), sorting is O(nlog(n)), and the merge-like comparison loop is O(n), the total time complexity is O(nlog(n)), where "n" is the length of the larger array.
imagesInUploadsFolder.sort(imgCmp);
imagesInDatabaseTable.sort(imgCmp);
// diff will hold the difference of the arrays
var diff = [];
var i=0, j=0, cmp;
while (i < imagesInUploadsFolder.length && j < imagesInDatabaseTable.length) {
cmp = cmp(imagesInUploadsFolder[i], imagesInDatabaseTable[j]);
if (cmp < 0) {
// up[i] < db[j]
++i;
diff.append(imagesInUploadsFolder[i]);
} else if (cmp > 0) {
// up[i] > db[j]
++j;
diff.append(imagesInDatabaseTable[j]);
} else {
// up[i] == db[j]
++i; ++j;
}
}
// one of the arrays may still have items; if so, loop over it and add the items
if (i < imagesInUploadsFolder.length) {
for (; i < imagesInUploadsFolder.length; ++i) {
diff.append(imagesInUploadsFolder[i]);
}
} else if (j < imagesInDatabaseTable.length)) {
for (; i < imagesInDatabaseTable.length; ++i) {
diff.append(imagesInDatabaseTable[i]);
}
}
// diff now holds items that are in only one of the two arrays.
If you can define a suitable object ID function, you can create an ancillary data structure that holds a set of elements. If accessing object properties is O(f(n)) (for hashes, f ≈ 1; for balanced trees, f = log(n)), then this approach is O(n*f(n)), so it should have no worse complexity than the sort-and-compare approach. Untested and inefficient implementation:
function Set(from) {
this.elements = {};
this.size = 0;
if (from) {
for (var i=0; i < from.length) {
this.add(from[i]);
}
}
}
Set.prototype.each = function(f) {
var eltId;
foreach (eltId in this.elements) {
f(this.elements[eltId], eltId);
}
};
Set.prototype.clone = function() {
var clone = new Set();
this.each(function(obj, id) {
clone.add(obj);
});
return clone;
};
Set.prototype.contains = function(obj) {
return obj.uniqueId() in this.elements;
};
Set.prototype.add = function(obj) {
var objId = obj.uniqueId();
if (! (objId in this.elements)) {
++this.size;
this.elements[objId] = obj;
}
return this;
};
Set.prototype.remove = function(obj) {
var objId = obj.uniqueId();
if (objId in this.elements) {
--this.size;
delete this.elements[objId];
}
return this;
};
Set.prototype.union = function(other) {
other.each(function(elt, id) { this.add(elt); });
return this;
};
Set.prototype.sub = function(other) {
other.each(function (elt, id) {
this.remove(elt);
});
return this;
};
Set.prototype.diff = function(other) {
var mine = this.clone();
mine.sub(other);
var others = other.clone();
others.sub(this);
mine.union(others);
return mine;
};
Set.prototype.toArray = function(obj) {
var arr = [];
this.each(function(elt, id) {
arr.append(elt);
});
return arr;
};
var uploadsSet = new Set(imagesInUploadsFolder),
dbSet = new Set(imagesInDatabaseTable),
imagesInJustOne = uploadsSet.diff(dbSet);
If you want both the union and difference of the arrays, you can define a suitable method on Set to more efficiently calculate them instead of using Set.diff and Set.union separately.