In the following code there is a console log of obj['mn'] which returns the length of that specific object which is 2. The problem with the code is that it doesn't count the multidimentional array, and only it counts the first array. The result should be 4 because there are 4 'mn' in total. What am I doing wrong?
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
for (var i = 0, j = arr.length; i < j; i++) {
if (obj[arr[i]]) {
obj[arr[i]]++;
}
}
console.log(obj['mn']);
This is what you're looking for:
var arr = [['ab','pq','mn','ab','mn','ab'],'mn','mn'];
var obj = { };
function count(arr, obj) {
for (var i = 0, j = arr.length; i < j; i++) {
if (Array.isArray(arr[i])) {
count(arr[i], obj);
}
else if (typeof obj[arr[i]] !== 'undefined') {
obj[arr[i]]++;
}
else {
obj[arr[i]] = 1;
}
}
return obj;
}
console.log(count(arr, obj));
This is a recursive implementation. When it gets to an array, the recursion get one level deeper.
You are calling obj[['ab','pq','mn','ab','mn','ab']], which is obviously not what you wanted.
You need a depth first search.
If arr[i] is an array, then you need to loop through that array.
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 have the below javascript array with me
var test =[{
Maths:{
ST1:10,
ST2:2,
ST3:15}
},
{
Science:{
ST1:50,
ST3:40}
}
]
I want to generate the array shown below out of this
var t = [{ST1:{
Maths:10,
Science:50
},
ST2:{
Maths:2,
Science:0
},
ST3:{
Maths:15,
Science:40
}
}]
I tried using the code shown below
for (var key in test) {
if (test.hasOwnProperty(key)) {
for (var key1 in test[key]){
//console.log(key1)}
var abc = test[key][key1];
for(var x in abc)
{
console.log(x+key1+abc[x])
}
}
}
}
I am new to this help me doing this.
This does mostly what you want...
var t = {};
for (var i = 0; i < test.length; i++) {
for (var name in test[i]) {
for (var level in test[i][name]) {
if (!t[level])
t[level] = {}
t[level][name] = test[i][name][level]
}
}
}
Only thing missing is to get the Science:0 for when a STx value is missing under a section.
DEMO: http://jsfiddle.net/eHwBC/
Result:
{
"ST1": {
"Maths": 10,
"Science": 50
},
"ST2": {
"Maths": 2
},
"ST3": {
"Maths": 15,
"Science": 40
}
}
Keep in mind that there's no guaranteed order when using for-in for enumeration.
If the labels (Math, Science, etc) are known in advance, then you can ensure that each object gets all labels.
If not, a separate loop can be done. Depending on the approach, it could be done before or after this main loop.
Do you know about JSON.stringify(t)?
It will convert an object literal to JSON.
Mozilla's documentation of this function is available at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/stringify.
You can also read this blog article for further explanation
Try this:
var test =[{
Maths:{
ST1:10,
ST2:2,
ST3:15
}
},
{
Science:{
ST1:50,
ST3:40}
}
];
var result = [];
for(i = 0; i <= test.length; i++){
var resultRow = {};
for(key in test[i]){
for(subKey in test[i][key]){
if(resultRow[subKey] == undefined){
resultRow[subKey] = {};
}
resultRow[subKey][key] = test[i][key][subKey];
}
}
result.push(resultRow);
}
Try like below,
/* Iterator start */
var t = {};
for (var i = 0; i < test.length; i++) { //Iterate Maths, Science,..
for (var key in test[i]) { //Iterate Math
for (var iKey in test[i][key]) { //Iterate ST1, ST2, ST3
var s = (t.hasOwnProperty(iKey))?t[iKey]:createObject();
s[key] = test[i][key][iKey];
t[iKey] = s;
}
}
}
/* Iterator End */
p = [];
p.push(t);
//^- p is what you want
// Separate function so you can add more items later without changing logic
function createObject () {
return {'Maths' : 0, 'Science': 0};
}
DEMO and Proof below,