Need to iterate through an array to get specific key: value pairs to add to empty object - javascript

For this problem, the function accepts an array of strings and returns an object. Keys are supposed to be the number of characters in a string and the value is supposed to be how many time a string with that amount of characters occurred.
I thought I was going somewhere and then I got stuck. I'd appreciate some help on this, I've tried googling it a million different ways but no luck. Thank you!
The result is supposed to look like : characterCount(['apple', 'berry', 'cherry']) // {5:2, 6:1}
function characterCount(arr){
var newObj = {};
var valueMax = 0;
var currentValue = 0;
for(var i=0; i < arr.length; i++){
var key = arr[i].length;
for(var z=0; z < arr.length; z++){
if (arr[z].length === arr[i].length){
currentValue ++;
if (currentValue > valueMax){
valueMax = currentValue;
}
}
}
newObj.key = "valueMax";
}
return newObj;
}

Look at the Array.prototype.reduce function. This allows you to take an array, iterate over each value, and return a new, reduced value.
function characterCount(arr) {
return arr.reduce((counts, str) => ({
...counts,
[str.length]: (counts[str.length] || 0) + 1
}), {});
}
const counts = characterCount(['apple', 'berry', 'cheery']);
console.log(counts);
Alternatively, you could use Object.assign instead of spreading the accumulator object.
function characterCount(arr) {
return arr.reduce((counts, str) => Object.assign(counts, {
[str.length]: (counts[str.length] || 0) + 1
}), {});
}
const counts = characterCount(['apple', 'berry', 'cheery']);
console.log(counts);

You could just reduce the array to accomplish the output
function characterCount( array ) {
return array.reduce( (agg, cur) => {
// get the length of the current item
const len = cur.length;
// increase the value of the key index with one (if none exist, start with 0)
agg[len] = (agg[len] || 0) + 1;
// return the next value for the iteration
return agg;
}, {});
}
console.log( characterCount(['apple', 'berry', 'cherry']) );

Using reduce is arguably better but here is a more straightforward approach.
function characterCount(arr) {
const countByLength = {};
for (let item of arr) {
countByLength[item.length] = (countByLength[item.length] || 0) + 1;
}
return countByLength;
}
console.log(characterCount(['apple', 'berry', 'cherry']));

Related

I have a array of string have to find all the common character present from all strings

I have a array of string.
let arr=["robin","rohit","roy"];
Need to find all the common character present in all the strings in array.
Output Eg: r,o
I have tried to create a function for above case with multiple loops but i want to know what should be the efficient way to achive it.
Here's a functional solution which will work with an array of any iterable value (not just strings), and uses object identity comparison for value equality:
function findCommon (iterA, iterB) {
const common = new Set();
const uniqueB = new Set(iterB);
for (const value of iterA) if (uniqueB.has(value)) common.add(value);
return common;
}
function findAllCommon (arrayOfIter) {
if (arrayOfIter.length === 0) return [];
let common = new Set(arrayOfIter[0]);
for (let i = 1; i < arrayOfIter.length; i += 1) {
common = findCommon(common, arrayOfIter[i]);
}
return [...common];
}
const arr = ['robin', 'rohit', 'roy'];
const result = findAllCommon(arr);
console.log(result);
const arr = ["roooooobin","rohit","roy"];
const commonChars = (arr) => {
const charsCount = arr.reduce((sum, word) => {
const wordChars = word.split('').reduce((ws, c) => {
ws[c] = 1;
return ws;
}, {});
Object.keys(wordChars).forEach((c) => {
sum[c] = (sum[c] || 0) + 1;
});
return sum;
}, {});
return Object.keys(charsCount).filter(key => charsCount[key] === arr.length);
}
console.log(commonChars(arr));
Okay, the idea is to count the amount of times each letter occurs but only counting 1 letter per string
let arr=["robin","rohit","roy"];
function commonLetter(array){
var count={} //object used for counting letters total
for(let i=0;i<array.length;i++){
//looping through the array
const cache={} //same letters only counted once here
for(let j=0;j<array[i].length;j++){
//looping through the string
let letter=array[i][j]
if(cache[letter]!==true){
//if letter not yet counted in this string
cache[letter]=true //well now it is counted in this string
count[letter]=(count[letter]||0)+1
//I don't say count[letter]++ because count[letter] may not be defined yet, hence (count[letter]||0)
}
}
}
return Object.keys(count)
.filter(letter=>count[letter]===array.length)
.join(',')
}
//usage
console.log(commonLetter(arr))
No matter which way you choose, you will still need to count all characters, you cannot get around O(n*2) as far as I know.
arr=["robin","rohit","roy"];
let commonChars = sumCommonCharacters(arr);
function sumCommonCharacters(arr) {
data = {};
for(let i = 0; i < arr.length; i++) {
for(let char in arr[i]) {
let key = arr[i][char];
data[key] = (data[key] != null) ? data[key]+1 : 1;
}
}
return data;
}
console.log(commonChars);
Here is a 1 liner if anyone interested
new Set(arr.map(d => [...d]).flat(Infinity).reduce((ac,d) => {(new RegExp(`(?:.*${d}.*){${arr.length}}`)).test(arr) && ac.push(d); return ac},[])) //{r,o}
You can use an object to check for the occurrences of each character. loop on the words in the array, then loop on the chars of each word.
let arr = ["robin","rohit","roy"];
const restWords = arr.slice(1);
const result = arr[0].split('').filter(char =>
restWords.every(word => word.includes(char)))
const uniqueChars = Array.from(new Set(result));
console.log(uniqueChars);

Iterate through array and average/sum values in it

I have an array of objects that I want to iterate through and sum some values if the keys exist in the sumList array and average all others. How can we best achieve this?
let sumList = ['TEST1', 'TEST2']
data.forEach(item => {
Object.keys(item).forEach(key => {
if (!result.hasOwnProperty(key)) {
result[key] = 0;
}
if(sumList.includes(key)) {
result[key] += item[key]
} else {
result[key] = (result[key] + item[key]) / 2;
}
});
});
The bug i am running into, i think has to do with the fact that initially value is 0... and it tried to divide 0 + the next value by 2. I would like to do this in the same loop insteam of first summing them then running another loop and averaging them.
You can use reduce() for the sum, filter() for the count, then use those two values to calculate the average:
const getValidKey = obj => sumList.find(key=>obj.hasOwnProperty(key));
const sum = data.reduce((accum, currentObj) => {
const key = getValidKey(currentObj);
return key ? accum + currentObj[key] : accum;
}, 0);
const count = data.filter(currentObj=>
getValidKey(currentObj) !== undefined
).length;
const average = sum/count;
Live Demo
There is nothing wrong with iterating through an array twice, as long as there aren't thousands of items. Code readability is more important than improving performance by a few milliseconds.
Should be like:
let sumList = ['TEST1', 'TEST2'], o, n, z, v, results = [];
for(let a of data){
o = {sums:0}; n = 0; z = 0;
for(let o of a){
for(let i in o){
v = o[i];
if(sumList.indexOf(i) === -1){
o.sums += v;
}
else{
z++; n += v;
}
}
}
o.avgs = z === 0 ? 0 : n/z;
results.push(o);
}

Get the sum of all specified elements in an array of objects

I have an array of objects as folllows
[
{"width":128.90663423245883,"height":160,"X":0,"Y":140},
{"width":277.0938568683375,"height":263,"X":128.90663423245883,"Y":37},
{"width":264.8267031014369,"height":261,"X":277.0938568683375,"Y":39},
{"width":229.14003389179788,"height":60,"X":264.8267031014369,"Y":240},
{"width":10.032771905968888,"height":177,"X":229.14003389179788,"Y":123}
]
I am looking to write a function that gets the sum of all 'width' elements in the object before the current.
Something like:
function getAllBefore(current) {
// here i want to get the sum of the previous 4 'width' elements in the object
}
getAllBefore(obj[5]);
For an easier and more reusable code pass to the method the object and the index, as follows:
function getAllBefore(obj, index){
var sum=0;
for(var i=0; i<index; i++){
sum+=obj[i].width;
}
return sum;
}
And call it like this:
getAllBefore(obj, 5);
Here is an example using a slice to first return the array with the correct length and the a reduce to return the sum
const getSum = (objNum, arr) => {
const newArr = arr.slice(0, objNum - 1)
return newArr.reduce((current, next) => {
return current + next.width;
}, 0)
}
and in ES5
var getSum = (objNum, arr) => {
vat newArr = arr.slice(0, objNum - 1)
return newArr.reduce(function(current, next) {
return current + next.width;
}, 0)
}
and in 1 line
const getSum = (objNum, arr) => arr.slice(0, objNum - 1).reduce((current, next) => current + next.width, 0)
Let's use reduce in JavaScript
var arr = [
{"width":128.90663423245883,"height":160,"X":0,"Y":140},
{"width":277.0938568683375,"height":263,"X":128.90663423245883,"Y":37},
{"width":264.8267031014369,"height":261,"X":277.0938568683375,"Y":39},
{"width":229.14003389179788,"height":60,"X":264.8267031014369,"Y":240},
{"width":10.032771905968888,"height":177,"X":229.14003389179788,"Y":123}
];
console.log(arr.reduce((acc, b) => acc + b.width, 0.0));
If you are looking for solution without knowing index of element but you want only to send object, then you will need to check all properties of current item with available items and you can do it like this:
var items = [
{"width":128.90663423245883,"height":160,"X":0,"Y":140},
{"width":277.0938568683375,"height":263,"X":128.90663423245883,"Y":37},
{"width":264.8267031014369,"height":261,"X":277.0938568683375,"Y":39},
{"width":229.14003389179788,"height":60,"X":264.8267031014369,"Y":240},
{"width":10.032771905968888,"height":177,"X":229.14003389179788,"Y":123}
];
function getAllBefore(current) {
var sum = 0;
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (current.width == item.width && current.height == item.height && current.X == item.X && current.Y == item.Y)
{
return sum;
}
sum += item.width;
}
}
getAllBefore(items[2]);
function count(stack) {
var totWidth = 0;
stack.forEach(function(element) {
totWidth = totWidth+element.width;
});
return totWidth;
}
working example

Select array index by object value

If I have an array like this:
var array = [{ID:1,value:'test1'},
{ID:3,value:'test3'},
{ID:2,value:'test2'}]
I want to select an index by the ID.
i.e, I want to somehow select ID:3, and get {ID:3,value:'test3'}.
What is the fastest and most lightweight way to do this?
Use array.filter:
var results = array.filter(function(x) { return x.ID == 3 });
It returns an array, so to get the object itself, you'd need [0] (if you're sure the object exists):
var result = array.filter(function(x) { return x.ID == 3 })[0];
Or else some kind of helper function:
function getById(id) {
var results = array.filter(function(x) { return x.ID == id });
return (results.length > 0 ? results[0] : null);
}
var result = getById(3);
With lodash you can use find with pluck-style input:
_.find(result, {ID: 3})
Using filter is not the fastest way because filter will always iterate through the entire array even if element being search for is the first element. This can perform poorly on larger arrays.
If you are looking for fastest way, simply looping through until the element is found might be best option. Something like below.
var findElement = function (array, inputId) {
for (var i = array.length - 1; i >= 0; i--) {
if (array[i].ID === inputId) {
return array[i];
}
}
};
findElement(array, 3);
I would go for something like this:
function arrayObjectIndexOf(myArray, property, searchTerm) {
for (var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i].property === searchTerm)
return myArray[i];
}
return -1;
}
In your case you should do:
arrayObjectIndexOf(array, id, 3);
var indexBy = function(array, property) {
var results = {};
(array||[]).forEach(function(object) {
results[object[property]] = object;
});
return results
};
which lets you var indexed = indexBy(array, "ID");

Get the index of the object inside an array, matching a condition

I have an array like this:
[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]
How can I get the index of the object that matches a condition, without iterating over the entire array?
For instance, given prop2=="yutu", I want to get index 1.
I saw .indexOf() but think it's used for simple arrays like ["a1","a2",...]. I also checked $.grep() but this returns objects, not the index.
As of 2016, you're supposed to use Array.findIndex (an ES2015/ES6 standard) for this:
a = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}];
index = a.findIndex(x => x.prop2 ==="yutu");
console.log(index);
It's supported in Google Chrome, Firefox and Edge. For Internet Explorer, there's a polyfill on the linked page.
Performance note
Function calls are expensive, therefore with really big arrays a simple loop will perform much better than findIndex:
let test = [];
for (let i = 0; i < 1e6; i++)
test.push({prop: i});
let search = test.length - 1;
let count = 100;
console.time('findIndex/predefined function');
let fn = obj => obj.prop === search;
for (let i = 0; i < count; i++)
test.findIndex(fn);
console.timeEnd('findIndex/predefined function');
console.time('findIndex/dynamic function');
for (let i = 0; i < count; i++)
test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');
console.time('loop');
for (let i = 0; i < count; i++) {
for (let index = 0; index < test.length; index++) {
if (test[index].prop === search) {
break;
}
}
}
console.timeEnd('loop');
As with most optimizations, this should be applied with care and only when actually needed.
How can I get the index of the object tha match a condition (without iterate along the array)?
You cannot, something has to iterate through the array (at least once).
If the condition changes a lot, then you'll have to loop through and look at the objects therein to see if they match the condition. However, on a system with ES5 features (or if you install a shim), that iteration can be done fairly concisely:
var index;
yourArray.some(function(entry, i) {
if (entry.prop2 == "yutu") {
index = i;
return true;
}
});
That uses the new(ish) Array#some function, which loops through the entries in the array until the function you give it returns true. The function I've given it saves the index of the matching entry, then returns true to stop the iteration.
Or of course, just use a for loop. Your various iteration options are covered in this other answer.
But if you're always going to be using the same property for this lookup, and if the property values are unique, you can loop just once and create an object to map them:
var prop2map = {};
yourArray.forEach(function(entry) {
prop2map[entry.prop2] = entry;
});
(Or, again, you could use a for loop or any of your other options.)
Then if you need to find the entry with prop2 = "yutu", you can do this:
var entry = prop2map["yutu"];
I call this "cross-indexing" the array. Naturally, if you remove or add entries (or change their prop2 values), you need to update your mapping object as well.
What TJ Crowder said, everyway will have some kind of hidden iteration, with lodash this becomes:
var index = _.findIndex(array, {prop2: 'yutu'})
var CarId = 23;
//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);
And for basic array numbers you can also do this:
var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1
You will get -1 if it cannot find a value in the array.
var index;
yourArray.some(function (elem, i) {
return elem.prop2 === 'yutu' ? (index = i, true) : false;
});
Iterate over all elements of array.
It returns either the index and true or false if the condition does not match.
Important is the explicit return value of true (or a value which boolean result is true). The single assignment is not sufficient, because of a possible index with 0 (Boolean(0) === false), which would not result an error but disables the break of the iteration.
Edit
An even shorter version of the above:
yourArray.some(function (elem, i) {
return elem.prop2 === 'yutu' && ~(index = i);
});
Using Array.map() and Array.indexOf(string)
const arr = [{
prop1: "abc",
prop2: "qwe"
}, {
prop1: "bnmb",
prop2: "yutu"
}, {
prop1: "zxvz",
prop2: "qwrq"
}]
const index = arr.map(i => i.prop2).indexOf("yutu");
console.log(index);
The best & fastest way to do this is:
const products = [
{ prop1: 'telephone', prop2: 996 },
{ prop1: 'computadora', prop2: 1999 },
{ prop1: 'bicicleta', prop2: 995 },
];
const index = products.findIndex(el => el.prop2 > 1000);
console.log(index); // 1
I have seen many solutions in the above.
Here I am using map function to find the index of the search text in an array object.
I am going to explain my answer with using students data.
step 1: create array object for the students(optional you can create your own array object).
var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];
step 2: Create variable to search text
var studentNameToSearch = "Divya";
step 3: Create variable to store matched index(here we use map function to iterate).
var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);
var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];
var studentNameToSearch = "Divya";
var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);
console.log(matchedIndex);
alert("Your search name index in array is:"+matchedIndex)
You can use the Array.prototype.some() in the following way (as mentioned in the other answers):
https://jsfiddle.net/h1d69exj/2/
function findIndexInData(data, property, value) {
var result = -1;
data.some(function (item, i) {
if (item[property] === value) {
result = i;
return true;
}
});
return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1
function findIndexByKeyValue(_array, key, value) {
for (var i = 0; i < _array.length; i++) {
if (_array[i][key] == value) {
return i;
}
}
return -1;
}
var a = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);
Try this code
var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Another easy way is :
function getIndex(items) {
for (const [index, item] of items.entries()) {
if (item.prop2 === 'yutu') {
return index;
}
}
}
const myIndex = getIndex(myArray);
Georg have already mentioned ES6 have Array.findIndex for this.
And some other answers are workaround for ES5 using Array.some method.
One more elegant approach can be
var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);
At the same time I will like to emphasize, Array.some may be implemented with binary or other efficient searching technique. So, it might perform better over for loop in some browser.
Why do you not want to iterate exactly ? The new Array.prototype.forEach are great for this purpose!
You can use a Binary Search Tree to find via a single method call if you want. This is a neat implementation of BTree and Red black Search tree in JS - https://github.com/vadimg/js_bintrees - but I'm not sure whether you can find the index at the same time.
One step using Array.reduce() - no jQuery
var items = [{id: 331}, {id: 220}, {id: 872}];
var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
if(item.id === searchIndexForId) {
console.log('found!');
searchIndex = index;
}
return searchIndex;
}, null);
will return null if index was not found.
var list = [
{prop1:"abc",prop2:"qwe"},
{prop1:"bnmb",prop2:"yutu"},
{prop1:"zxvz",prop2:"qwrq"}
];
var findProp = p => {
var index = -1;
$.each(list, (i, o) => {
if(o.prop2 == p) {
index = i;
return false; // break
}
});
return index; // -1 == not found, else == index
}

Categories