This question already has answers here:
Count unique elements in array without sorting
(9 answers)
Closed 6 years ago.
Okay I researched this one and couldn't find an answer here so hopefully this isn't a duplicate. I'm also trying not to be specific in order to figure this out on my own.
var arr = ['cat','car','cat','dog','car','dog']
function orgNums(input) {
var count = 0;
var obj = {};
for (var i = 0; i < input.length; i++) {
if (input[i] === 'cat')
obj['cat'] = count++;
}
return obj;
}
I want it to return {cat:2} but I'm getting {cat:1}
Eventually I want it to return {cat:2, car:1, dog:2, gerbil:1}
So I tried using obj[cat] = ++count and I'm getting the answer I want, but when I try a second if statement: if input[i] === 'dog', obj[dog] = ++countI get {cat:2, dog:4}. I noticed that it's taking what count already is at, 0, then moves it to 2 to count cat, then moves it to 4, taking the dog count of 2 and adding 2 to it. How do I prevent that from happening so that count restarts at 0 each time?
EDIT:
So this works beautifully
var arr = ['cat', 'car', 'cat', 'dog', 'car', 'dog']
function orgNums(input) {
var obj = {};
for (var i = 0; i < input.length; i++) {
obj[input[i]] = obj[input[i]] || 0;
obj[input[i]]++;
}
return obj;
}
console.log(orgNums(arr));
but the final output i actually want is:
[
{cat:1
dog:2
}
{car:2
}
]
So I tried throwing in an if statement like this:
if (input[i] === 'cat'||'dog')
but it's still throwing car into the object. I'll try to figure out the multiple objects in the array. Thanks again!
You could just reduce the array, and count the keys as you go
var arr = ['cat', 'car', 'cat', 'dog', 'car', 'dog', 'horse'];
function orgNums(input) {
return input.reduce((a, b) => {
return b in a ? a[b]++ : a[b] = 1, a;
}, {});
}
console.log(orgNums(arr));
The assignment of count, which is used in the loop, does not work in this case, because of the postfix increment count++. This gives you the value of the counter and increment later, If you take the prefix increment ++count, you get the incremented value assigned.
// Postfix
var x = 3;
y = x++; // y = 3, x = 4
// Prefix
var a = 2;
b = ++a; // a = 3, b = 3
But you can omit the variable and count directly with a property of the object. for all items in one loop.
You could use the element as key for the object. Then assign with zero, if not exist and increment.
var arr = ['cat', 'car', 'cat', 'dog', 'car', 'dog']
function orgNums(input) {
var obj = {};
for (var i = 0; i < input.length; i++) {
obj[input[i]] = obj[input[i]] || 0;
obj[input[i]]++;
}
return obj;
}
console.log(orgNums(arr));
A more compact version of the above with Array#forEach
var arr = ['cat', 'car', 'cat', 'dog', 'car', 'dog']
function orgNums(input) {
var obj = {};
input.forEach(function (item) {
obj[item] = (obj[item] || 0) + 1;
});
return obj;
}
console.log(orgNums(arr));
Related
I am trying to write a function that accepts an array of strings as an argument. I want to return the array of strings sorted first by number of vowels and then alphabetically.
Input: ['dog', 'cat', 'elephant', 'hippo', 'goat']
Output: ['cat', 'dog', 'goat', 'hippo', 'elephant']
function vowelMatching(vowels) {
return vowels.match(/[aeiou]/ig) || [];
//The 'i' in regex accounts for capitals
}
function arrangeByVowels(array) {
const outputArray = [];
console.log(array.length)
console.log(outputArray.length)
for(let x=0; array.length === outputArray.length; x++) {
// let x = 0
const filterArray = [];
for(let i =0; i<array.length; i++) {
//console.log(vowelMatching(array[i]).length)
if (vowelMatching(array[i]).length === x) {
filterArray.push(array[i])
}
}
//console.log(filterArray.sort())
outputArray.push(...filterArray.sort())
}
return outputArray
}
console.log(arrangeByVowels(['dog', 'gAg', 'qq', 'cat', 'elephant', 'hippo', 'goat']))
I am using a nested for loop to achieve this. If I assign a value to x for example let x = 1 and I comment out the outer for loop, it will return all the words with 1 vowel in alphabetical order. (This is the result I am after)
I want to loop through x until array.length === outputArray.length but at the moment this code is returning an empty array, and I am not sure why.
I think I am close, but have no idea where I am going wrong. What am I doing wrong?
As a follow up answer to your actual question....
The issue is the logic in your initial for loop
for(let x=0; array.length === outputArray.length; x++)
Your condition array.length === outputArray.length will always initially return false as your output array is a different length to your initial array. This will instantly end the for loop because the condition to continue the iteration has failed.
The for loop is essentially while(contition is true) increment x; Your condition starts false.
to correct it simple change the condition so it is always true until your criteria is met:
for(let x=0; outputArray.length < array.length; x++)
function vowelMatching(vowels) {
return vowels.match(/[aeiou]/ig) || [];
}
function arrangeByVowels(array) {
const outputArray = [];
for(let x=0; outputArray.length < array.length; x++) { // Logic error was here.
const filterArray = [];
for(let i =0; i<array.length; i++) {
if (vowelMatching(array[i]).length === x) {
filterArray.push(array[i])
}
}
outputArray.push(...filterArray.sort())
}
return outputArray
}
console.log(arrangeByVowels(['dog', 'gAg', 'porcupine', 'qq', 'alligator', 'cat', 'elephant', 'albatross', 'hippo', 'goat', 'potato', 'banana','aardvark' ]))
This can be done in a single .sort();
let source = ['dog', 'gAg', 'qq', 'cat', 'elephant', 'hippo', 'goat', 'arose', 'unity', 'arise']
let result = source.sort((a,b) => {
let aVowels = a.match(/[aeiou]/gi) || [];
let bVowels = b.match(/[aeiou]/gi) || [];
return aVowels.length === bVowels.length ?
(a > b ? 1 : -1) : // same number of vowels so compare alphabetically
(aVowels.length > bVowels.length ? 1 : -1) // different number of vowels so compare lengths
})
console.log(result);
I am attempting to compare two array of object and assigning them a similarity score based of common items in the array.
I was able to compare the arrays but I am running into issue with using the same concept on array of objects.
let array1 = [{key1:['item1','item2','item3','item4']},{key2:['event3','event4']}];
let array2 = [{key1:['item1','item4','item2','item8']},{key2:['event4','event2']}];
let arrayA=['item1','item2','item3','item4'];
let arrayB=['item1','item4','item2','item8'];
function SimilarityPercentage(arrayA,arrayB){
let answer =arrayA.filter(function(item) {
return arrayB.indexOf(item) >= 0;
}).length
return answer/(Math.max(arrayA.length,arrayB.length))*100
}
console.log(SimilarityPercentage(arrayA,arrayB));// 75
Given array1 and array2 , I would like the result split out a similarity score, similar to the function above. I would like to use the rand index calculation : https://en.wikipedia.org/wiki/Rand_index#targetText=The%20Rand%20index%20or%20Rand,is%20the%20adjusted%20Rand%20index.
You could get the values and calculate the common score.
function similarityPercentage(arrayA, arrayB) {
return 100 * arrayA.filter(Set.prototype.has, new Set(arrayB)).length / Math.max(arrayA.length, arrayB.length);
}
function similarities(a, b) {
var parts = a.map((o, i) => similarityPercentage(Object.values(o)[0], Object.values(b[i])[0]));
return parts.reduce((a, b) => a + b, 0) / parts.length;
}
var array1 = [{ key1: ['item1', 'item2', 'item3', 'item4'] }, { key2: ['event3', 'event4'] }],
array2 = [{ key1: ['item1', 'item4', 'item2', 'item8'] }, { key2: ['event4', 'event2'] }],
arrayA = ['item1', 'item2', 'item3', 'item4'],
arrayB = ['item1', 'item4', 'item2', 'item8'];
console.log(similarityPercentage(arrayA, arrayB)); // 75
console.log(similarities(array1, array2)); // 62.5
You could do something like this:
var array1 = [val1,val2,val3];
var array2 = [val1,val4,val5];
var sim = [];
var simscore = 9;
if (array1.length > array2.length) {
for (var i = 0; i < array1.length; i++) {
if(array1[i] == array2[i]) {
sim.push(i);
simarr = array1;
simscore ++;
}
}
}else{
for (var i = 0; i < array2.length; i++) {
if(array1[i] == array2[i]) {
sim.push(i);
simarr = array2;
simscore ++;
}
}
}
console.log(sim);
console.log("Percent similar: ", simscore/simarr.length);
This will add the similar index to an array sim and increase the count of similar indexes by 1, always for the longer array, then print the percent of similarity.
First of all, your sample arrays are not well-structured, and your problem can be done more quickly if you restructure them.
Since you have not provided a formula for calculating the similarity between array1 and array2, I assume that every each of these arrays has equal length, and every item in them represents an object which has only one property (with the same name), and that property itself is an array. One obvious approach is to calculate every similarity score of the related child arrays of these two arrays to be calculated and then calculate the total similarity by averaging every key's similarity score.
Assumptions:
array1 and array2 have equal length
The nth element of array1 has only one property with the name keyFoo and the nth element of array2 also has only one property with the name keyFoo and keyFoo property of these two arrays are arrays themselves and must be compared to each other.
This quickly can be done using already provided SimilarityPercentage function:
function SimilarityPercentage2 (array1, array2) {
let similaritySum = 0;
for (let i = 0; i < array1.length; i++) {
const elem = array1[i];
const key = Object.keys(elem)[0];
similaritySum += SimilarityPercentage(elem[key], array2[i][key]);
}
return similaritySum / array1.length;
}
console.log(SimilarityPercentage2(array1, array2));
// output: 62.5
This question already has answers here:
Why does JavaScript map function return undefined?
(13 answers)
Closed last month.
So I have 24 "person" objects, which I created using "names" array, so that "dude" names are repeating;
Next I made a function that compares some random numbers to object id-s, and if they are equal,then I am trying to make new array of person names that go with that id.
(I'm sorry if this sounds too complicated, but I really don't understand why my map method doesn't work.)
Here 2 versions of my code. The first one works, and does what I want.
var names = ["jim", "jack", "aaron", "hugh", "jeff", "cameron", "allen", "charlie"];
var len = 3,
arr1 = [],
counter = 1;
for (var i = 0; i < len; i++) {
names.forEach(name => {
arr1.push({
id: counter,
dude: name
});
counter++;
});
}
console.log(arr1);
function checkName(nums) {
var namesarr = [];
for (var i = 0; i < arr1.length; i++) {
nums.forEach(function(num) {
if (num === arr1[i].id) {
namesarr.push(arr1[i].dude);
}
});
}
return (namesarr);
};
console.log(checkName([1, 3, 6]));
But in second version, my map function returns undefined, and I really don't understand why?!
var names = ["jim", "jack", "aaron", "hugh", "jeff", "cameron", "allen", "charlie"];
var len = 3,
arr1 = [],
counter = 1;
for (var i = 0; i < len; i++) {
names.forEach(name => {
arr1.push({
id: counter,
dude: name
});
counter++;
});
}
console.log(arr1);
function checkName(nums) {
var namesarr;
for (var i = 0; i < arr1.length; i++) {
namesarr = nums.map(function(num) {
if (num === arr1[i].id) {
return arr1[i].dude;
}
});
}
return (namesarr);
};
console.log(checkName([1, 3, 6]));
You're overwriting the namesarr variable on each iteration of the loop. I think you meant to add to it on each pass, rather than overwrite it. To do that, you can use the array .concat method.
Then, finally, make sure to filter all the undefined values from the result before you return it.
var names = ["jim", "jack", "aaron", "hugh", "jeff", "cameron", "allen", "charlie"];
var len = 3,
arr1 = [],
counter = 1;
for (var i = 0; i < len; i++) {
names.forEach(name => {
arr1.push({
id: counter,
dude: name
});
counter++;
});
}
console.log(arr1);
function checkName(nums) {
var namesarr = [];
for (var i = 0; i < arr1.length; i++) {
namesarr = namesarr.concat(nums.map(function(num) {
if(num === arr1[i].id) {
return arr1[i].dude;
}
}));
}
return (namesarr.filter(Boolean));
};
console.log(checkName([1,3,6]));
The result of map() is an array of all the returned values. If a function doesn't execute a return statement, it's equivalent to ending with return undefined.
In your second version, whenever the if condition fails, you don't execute return arr1[i].dude;, so it's returning undefined by default. It's as if you'd written:
namesarr = nums.map(function(num) {
if (num === arr1[i].id) {
return arr1[i].dude;
} else {
return undefined;
}
});
The other difference between your two versions of the code is that the second version reassigns namesarr each time through the for loop. So you're just printing the result of the last iteration.
The first version assigns it once before the loop, and adds to it only when the if condition succeeds, so you get the elements from all iterations.
Your map function doesn't return something for all the items in the array (because of the if) so some values in the result array will be undefined.
Plus, your map is inside a loop that loops over arr1, so for each iteration of that loop, the array namesarr get overridden. So the map will be as if it was applied only for the last element in arr1, thus if nums contain N elements then namesarr will have at least N - 1 undefined values in it (N - 1 if the last object of arr1 matches nums, N if not).
The problem is better solved using reduce instead of map:
function checkName(nums) {
return arr1.reduce(function(namesarr, obj) { // for each object obj in the array arr1
if(nums.indexOf(obj.id) !== -1) { // if the object's id is in the array nums
namesarr.push(obj.dude); // then add the object's dude to the array namesarr
}
return namesarr;
}, []); // the empty array to initialize namesarr
}
I am trying to create a new array with just the object values of myArray. My code below returns newArray with both Objects stored, but I am stuck on how to get the 'values' out and put them into the array. I am used to for-in on Objects, but not sure how to access objects when they are stored in an Array.
var myArray = [{first: 'michael', last: 'jordan'}, {first: 'brett', last: 'favre'}];
var myFunc = function (values) {
newArray = [];
for (var i = 0; i < values.length; i += 1) {
newArray.push(values);
}
return newArray;
}
Try this:
var myFunc = function (values) {
newArray = [];
for (var i = 0; i < values.length; i += 1) {
for(var e in values[i]) {
newArray.push(values[i][e]);
}
}
return newArray;
}
Demonstration
Note that this method is 'shallow'—that is, it will only get values one-level deep. If you had a structure like [{foo:{bar:'baz'}}], the result would be [{bar:'baz'}].
Consider this example.
var array = ['a','b','c','d'];
The index of 'a' is 0
The index of 'b' is 1
and so forth...
Therefore:
array[0] = 'a'
Next example:
var array = [ { foo: 'bar' }, { hello: 'world' } ];
The index of the first object is 0
The index of the second object is 1
Therefore:
array[0] = { foo: 'bar' }
To access a property of that object, you can do this:
array[0]['foo'] = 'bar';
So, you can do something like this, to iterate over the members of an object, when that object is inside of an array:
var array = [ { foo: 'bar' }, { hello: 'world' } ],
newArray = [];
var i, len = array.length;
for( i=0; i<len; i++ ) {
for ( e in array[i] ) {
newArray.push(array[i][e]);
}
}
OUTPUT:
newArray = ['bar', 'world'];
This example uses the relatively new Object.keys() and Array.reduce():
var values = myArray.reduce(function(prev, current) {
return prev.concat(Object.keys(current).map(function(key) {
return current[key];
}));
}, []);
This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 3 years ago.
I have two arrays, and I want to be able to compare the two and only return the values that match. For example both arrays have the value cat so that is what will be returned. I haven't found anything like this. What would be the best way to return similarities?
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
//if value in array1 is equal to value in array2 then return match: cat
You can use :
const intersection = array1.filter(element => array2.includes(element));
Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1, then push it onto the returned array.
Array.prototype.diff = function(arr2) {
var ret = [];
for(var i in this) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in, you can sort both arrays first to reindex all their values:
Array.prototype.diff = function(arr2) {
var ret = [];
this.sort();
arr2.sort();
for(var i = 0; i < this.length; i += 1) {
if(arr2.indexOf(this[i]) > -1){
ret.push(this[i]);
}
}
return ret;
};
Usage would look like:
var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];
console.log(array1.diff(array2));
If you have an issue/problem with extending the Array prototype, you could easily change this to a function.
var diff = function(arr, arr2) {
And you'd change anywhere where the func originally said this to arr2.
I found a slight alteration on what #jota3 suggested worked perfectly for me.
var intersections = array1.filter(e => array2.indexOf(e) !== -1);
Hope this helps!
This function runs in O(n log(n) + m log(m)) compared to O(n*m) (as seen in the other solutions with loops/indexOf) which can be useful if you are dealing with lots of values.
However, because neither "a" > 1 nor "a" < 1, this only works for elements of the same type.
function intersect_arrays(a, b) {
var sorted_a = a.concat().sort();
var sorted_b = b.concat().sort();
var common = [];
var a_i = 0;
var b_i = 0;
while (a_i < a.length
&& b_i < b.length)
{
if (sorted_a[a_i] === sorted_b[b_i]) {
common.push(sorted_a[a_i]);
a_i++;
b_i++;
}
else if(sorted_a[a_i] < sorted_b[b_i]) {
a_i++;
}
else {
b_i++;
}
}
return common;
}
Example:
var array1 = ["cat", "sum", "fun", "hut"], //modified for additional match
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
intersect_arrays(array1, array2);
>> ["cat", "hut"]
Loop through the second array each time you iterate over an element in the first array, then check for matches.
var array1 = ["cat", "sum", "fun", "run"],
array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
function getMatch(a, b) {
var matches = [];
for ( var i = 0; i < a.length; i++ ) {
for ( var e = 0; e < b.length; e++ ) {
if ( a[i] === b[e] ) matches.push( a[i] );
}
}
return matches;
}
getMatch(array1, array2); // ["cat"]
var array1 = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array3 = array2.filter(function(obj) {
return array1.indexOf(obj) !== -1;
});
You can use javascript function .find()
As it says in MDN, it will return the first value that is true. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.find((val, index) => {
console.log('index', index) // Stops at 0
return array2.includes(val)
})
console.log(found)
Or use .filter(), which loops through every elements first, then give back the result to you.
var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
found = array1.filter((val, index) => {
console.log('index', index) // Stops at array1.length - 1
return array2.includes(val)
})
console.log(found)
use lodash
GLOBAL.utils = require('lodash')
var arr1 = ['first' , 'second'];
var arr2 = ['second '];
var result = utils.difference(arr1 , arr2);
console.log ( "result :" + result );
Libraries like underscore and lodash have a utility method called intersection to find matches in arrays passed in. Take a look at: http://underscorejs.org/#intersection
Done as a answer so I can do formatting...
This is the the process you need to go through. Looping through an array for the specifics.
create an empty array
loop through array1, element by element. {
loop through array2, element by element {
if array1.element == array2.element {
add to your new array
}
}
}
If your values are non-null strings or numbers, you can use an object as a dictionary:
var map = {}, result = [], i;
for (i = 0; i < array1.length; ++i) {
map[array1[i]] = 1;
}
for (i = 0; i < array2.length; ++i) {
if (map[array2[i]] === 1) {
result.push(array2[i]);
// avoid returning a value twice if it appears twice in array 2
map[array2[i]] = 0;
}
}
return result;
With some ES6:
let sortedArray = [];
firstArr.map((first) => {
sortedArray[defaultArray.findIndex(def => def === first)] = first;
});
sortedArray = sortedArray.filter(v => v);
This snippet also sorts the firstArr based on the order of the defaultArray
like:
let firstArr = ['apple', 'kiwi', 'banana'];
let defaultArray = ['kiwi', 'apple', 'pear'];
...
console.log(sortedArray);
// ['kiwi', 'apple'];
Iterate on array1 and find the indexof element present in array2.
var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","sun", "hut", "gut"];
var str='';
for(var i=0;i<array1.length;i++){
if(array2.indexOf(array1[i]) != -1){
str+=array1[i]+' ';
};
}
console.log(str)