in my for element of array loop, I want to access the elements besides the current one. Specifically, the previous or next element. I would also like this to reach across the first/last element barrier. How can this be achieved?
ie. given:
my_fruits = ['apple', 'banana', 'grapes', 'blueberries']
for (const fruit of my_fruits) {
// When fruit === 'banana', I want to access 'apple',
// when fruit === 'blueberries' I want to access 'grapes'.
// Also when it's the last element, I want to acknowledge that and access the first.
}
Due to how I'm dealing with async/await in this local, .forEach is something I'd prefer to avoid.
Thanks
You should use forEach loop and use the second parameter which is index.
const arr = ['apple', 'banana', 'grapes', 'blueberries']
arr.forEach((x,i) => {
let prev = i > 0 ? arr[i - 1] : null;
let next = i < arr.length ? arr[i + 1] : null;
console.log(`current:${x} next:${next} previous: ${prev}`)
})
If you don't want to use forEach you can use for..in. But besure about this you are not adding any properties other than indexes on the array.
const arr = ['apple', 'banana', 'grapes', 'blueberries']
for(let i in arr){
console.log(`current:${arr[+i]} next:${arr[+i+1]} previous: ${arr[+i-1]}`)
}
You could use forEach. The third parameter of the callback function is the array. So, you could destructure it to get the [i-1] and [i+1] th items
const my_fruits = ['apple', 'banana', 'grapes', 'blueberries']
my_fruits.forEach((item, i, { [i-1]: prev, [i+1]: next }) => {
console.log(item, prev, next)
})
You can access the index of the current element.
var my_fruits = ['apple', 'banana', 'grapes', 'blueberries']
for (const [index,value] of my_fruits.entries()) {
if(index) console.log(my_fruits[index-1])
}
You can use a regular for (let i = 0; i < len; i++)
let my_fruits = ['apple', 'banana', 'grapes', 'blueberries'];
for (let i = 0, len = my_fruits.length; i < len; i++)
{
if (i == 0)
{
console.log("I am at first iteration. The last item is : "+ my_fruits[len - 1]);
}
if (i > 0)
{
console.log("I have now : " + my_fruits[i] + " and I have access to " + my_fruits[i - 1]);
}
if (i + 1 == len)
{
console.log("I am at last iteration. The first item is : "+ my_fruits[i - 1]);
}
}
I hope that what You need
const my_fruits = ['apple', 'banana', 'grapes', 'blueberries']
for (let fruit in my_fruits) {
fruit = parseInt(fruit);
if (! my_fruits[fruit + -1]) {
console.log(my_fruits[0] + " => " + my_fruits[fruit + my_fruits.length - 1]);
} else {
console.log(my_fruits[fruit] + " => " + my_fruits[fruit + -1]);
}
}
const arr = ['apple', 'banana', 'grapes', 'blueberries']
arr.forEach((x,i) => {
let prev = i > 0 ? arr[i - 1] : null;
let next = i + 1 < arr.length ? arr[i + 1] : null;
console.log(`current:${x} next:${next} previous: ${prev}`)
})
I used Maheer Ali's code above, but I had to make a change.
I put i + 1 < arr.length instead of i < arr.length because otherwise it always returns true (the index, starting from 0, will always be less than the length of the array, if it exists).
Related
I am looking at a reduce example and don't quite understand what (tally[fruit] || 0) + 1 ; is doing. I would have wrote it as tally[fruit] = !!tally[fruit] ? 0 : 1 ; . Is that the same thing it's trying to do?
const fruitBasket = ['banana', 'cherry', 'orange', 'apple', 'cherry', 'orange', 'apple', 'banana', 'cherry', 'orange', 'fig' ];
const count = fruitBasket.reduce( (tally, fruit) => {
tally[fruit] = (tally[fruit] || 0) + 1 ;
return tally;
} , {})
count // { banana: 2, cherry: 3, orange: 3, apple: 2, fig: 1 }
The codes are not equivalent.
Doing
tally[fruit] = (tally[fruit] || 0) + 1 ;
will result in each fruit being counted up on the object. For example, iterating over ['a', 'b', 'b'], starting with the empty object:
tally[fruit] = (tally[fruit] || 0) + 1;
tally.a = (tally.a || 0) + 1;
tally.a = (0) + 1;
tally.a = 1;
tally.b = (tally.b || 0) + 1;
tally.b = (0) + 1;
tally.b = 1;
tally.b = (tally.b || 0) + 1;
tally.b = (1) + 1;
tally.b = 2;
resulting in { a: 1, b: 2 }.
The other code does something pretty different:
tally[fruit] = !!tally[fruit] ? 0 : 1;
Since tally[fruit] always starts out undefined, the 1 branch will be entered, but then on further iterations over the same fruit, since 1 is truthy, the 0 branch will still be entered. It'll toggle between 0 and 1. You'd get { a: 1, b: 0 }. Probably not desirable.
const count = ['a', 'b', 'b'].reduce( (tally, fruit) => {
tally[fruit] = !!tally[fruit] ? 0 : 1 ;
return tally;
} , {})
console.log(count);
What it is doing is the order of evaluation.the first part evaluated is the one with parentheses so first it will be
either the number that is already in your accumulator for instance in the case when that fruit has already been counted. or a 0 when it is the first time the fruit is encountered to allow the adding operation to succeed.
below are some examples as to why the grouping operator is needed:
let fruities={banana:5};
const goodIncrementer = (fruities,fruitName) => (fruities[fruitName]||0)+1;
const badIncrementer = (fruities,fruitName) => fruities[fruitName]||0+1;
console.log("goodie",goodIncrementer(fruities,"banana"))
console.log("baddie",badIncrementer(fruities,"banana"))
tally[fruit] || 0 is just a shorthand version of preventing undefined value from creeping into your logic flow.
What this code does is that , it checks if tally[fruit] is defined, which means checking if tally object has that fruit as key or not. If key exist, then use the value otherwise, default to 0
In normal syntax , this code would do the exact same thing
if( tally[fruit] ) {
tally[fruit] = tally[fruit] + 1;
}else {
tally[fruit] = 1;
}
I have
let array = ['mango', 'mango_shake','banana', 'banana_shake', 'cherry', 'cherry_shake', 'Strawberry', 'Strawberry_shake', ...n];
What i want to do is:
let target = [{'fruit': 'mango', 'drink': 'mango_shake'},
{'fruit': 'banana', 'drink': 'banana_shake'}, ...n];
How can i do it?
You can simply loop through array and create an array of object like this
let array = ['mango', 'mango_shake', 'banana', 'banana_shake', 'cherry', 'cherry_shake', 'Strawberry', 'Strawberry_shake'];
var res = [];
for (var i = 0; i < array.length; i = i + 2) {
var ob = {};
ob.fruit = array[i];
ob.drink = array[i + 1];
res.push(ob);
}
console.log(res);
Note: This answer assumes the fruit and its corresponding drink are always right beside each other in the array. This will give wrong answers if items are out of order.
Just iterate over your original array until it is empty and take out pairs and map them to objects:
const result = [];
while(array.length)
result.push((([fruit, drink]) => ({fruit, drink}))(array.splice(0, 2));
(In case this is your homework: i think it will be harder to explain to your teacher how it works instead of just trying it on your own :))
You can iterate over the array to combine every other item
let target = {};
array.forEach( (curr, indx, arr) => {
if (indx %2 == 1) {
target[arr[indx-1]] = curr
}
});
This question already has answers here:
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
(97 answers)
Closed 6 years ago.
Okay I'm trying to search an array and find the duplicates and return the number of times each of the duplicates occurs. This is what I have so far, I need to pass in two arguments first the array being searched and then a specific term within that array:
countMatchingElements = function(arr, searchTerm){
var count = 0;
for(i = 0; i <= arr.length; i++){
count++;
}
return count;
};
Array I want to search:
var arrayToSearch = ['apple','orange','pear','orange','orange','pear'];
var arrayToSearch = ['apple', 'orange', 'pear', 'orange', 'orange', 'pear'];
var counter = {};
arrayToSearch.forEach(function(e) {
if (!counter[e]) {
counter[e] = 1;
} else {
counter[e] += 1
}
});
console.log(counter); //{ apple: 1, orange: 3, pear: 2 }
Something like this might do the trick:
var arrayToSearch = ['apple', 'orange', 'pear', 'orange', 'orange', 'pear'];
countMatchingElements = function(arr, searchTerm) {
return arr.filter(function(item) { return item === searchTerm; }).length;
};
document.writeln('"orange" appears ' + countMatchingElements(arrayToSearch, 'orange') + ' times.');
Say I have an array that goes something like:
fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana']
I want to make an array fruits that consists of the fruits found in fruit basket, sorted in order of most frequently occurring fruit. (If there are ties I don't care about ordering.)
So one valid value for fruits is:
['banana', 'orange', 'apple', 'pear']
What's the most concise way to achieve this using LoDash? I don't care about run time performance.
First you'd count the occurences
var x = _.chain(fruit_basket).countBy(); // {apple: 1, orange: 1, banana: 2, pear: 1}
Then you'd pair them and sort by the number of occurences, using reverse to get the largest number first
var y = x.toPairs().sortBy(1).reverse(); //[["banana",2],["pear",1],["orange",1],["apple",1]]
Then you'd just map back the keys, and get the value as an array
var arr = y.map(0).value(); // ['banana', 'orange', 'apple', 'pear']
All chained together, it looks like
var arr = _.chain(fruit_basket).countBy().toPairs().sortBy(1).reverse().map(0).value();
Without loDash, something like this would do it
var fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana'];
var o = {};
fruit_basket.forEach(function(item) {
item in o ? o[item] += 1 : o[item] = 1;
});
var arr = Object.keys(o).sort(function(a, b) {
return o[a] < o[b];
});
Here's my take on this.
It doesn't use lodash as the question asks for. It's a vanilla alternative. I feel this could be valuable to people who land here from Google and don't want to use lodash (that's how I got here, at least).
const orderByCountAndDedupe = arr => {
const counts = new Map();
arr.forEach( item => {
if ( !counts.has(item) ) {
counts.set(item, 1);
} else {
counts.set(item, counts.get(item)+1);
}
});
return (
Array.from(counts)
.sort( (a, b) => b[1] - a[1])
.map( ([originalItem, count]) => originalItem)
);
};
An approach using for loop Array.prototype.splice()
var fruit_basket = ['apple', 'orange', 'banana', 'pear', 'banana'];
var res = [];
for (var i = 0; i < fruit_basket.length; i++) {
var index = res.indexOf(fruit_basket[i]);
// if current item does not exist in `res`
// push current item to `res`
if (index == -1) {
res.push(fruit_basket[i])
} else {
// else remove current item , set current item at index `0` of `res`
res.splice(index, 1);
res.splice(0, 0, fruit_basket[i])
}
}
console.log(res)
You can count occurences using _.countBy and then use it in _.sortBy:
var counter = _.countBy(fruit_basket)
var result = _(fruit_basket).uniq().sortBy(fruit => counter[fruit]).reverse().value()
I'm looking for an elegant way of sorting an array by the occurrence of its elements.
For example, in:
['pear', 'apple', 'orange', 'apple', 'orange', 'apple']
the output should look like
['apple', 'orange', 'pear']
I have tried to loop through the array and save the occurrence in another temporary array, but this solution was quite bad.
It would require two loops.
var arr = ['pear', 'apple', 'orange', 'apple', 'orange', 'apple'];
//find the counts using reduce
var cnts = arr.reduce( function (obj, val) {
obj[val] = (obj[val] || 0) + 1;
return obj;
}, {} );
//Use the keys of the object to get all the values of the array
//and sort those keys by their counts
var sorted = Object.keys(cnts).sort( function(a,b) {
return cnts[b] - cnts[a];
});
console.log(sorted);
Map the values into a fruit→count associated object:
var counted = fruits.reduce(function (acc, fruit) {
if (acc[fruit]) {
acc[fruit]++;
} else {
acc[fruit] = 1;
}
return acc;
}, {});
Map that object into a sortable array:
var assoc = counted.keys().map(function (fruit) {
return [fruit, counted[fruit]];
});
Sort the array:
assoc.sort(function (a, b) { return a[1] - b[1]; });
Extract the values:
var result = assoc.map(function (i) { return i[0]; });
You can reduce your array to remove duplicates and then sort with custom comparator:
var sorted = ['pear', 'apple', 'orange', 'apple', 'orange', 'apple'].reduce(function(result, item) {
result.every(function(i) {
return i != item;
}) && result.push(item);
return result;
}, []).sort(function(i1, i2) {
return i1 > i2;
});
console.log(sorted);
With linq.js it is pretty easy (with example):
var array = ['pear', 'apple', 'orange', 'apple', 'orange', 'apple'];
var res = Enumerable.From(array).GroupBy(function (x) { return x; }).Select(function (x) { return { key: x.Key(), count: x.Count() } }).OrderByDescending(function (x) { return x.count }).Select(function (x) { return x.key}).ToArray();
You could try out lodash. All you need to do is group, sort, then map and you are done.
var arr = ['pear', 'apple', 'orange', 'apple', 'orange', 'apple'];
document.body.innerHTML = _(arr).chain().groupBy()
.sortBy(function(a) {
return -a.length; // <- Note: Remove the negation to sort in ascending order.
}).map(function(a) {
return a[0];
}).value().join(', ');
<script src="https://cdn.rawgit.com/lodash/lodash/master/dist/lodash.js"></script>
Try this:
var arr = ['pear', 'apple', 'orange', 'apple', 'orange', 'apple'];
var result = [];
var count = 0;
arr.sort();
for (var i = 0; i < arr.length; i++) {
count++;
if (arr[i] != arr[i + 1]) {
result.push({
"count": count,
"value": arr[i]
});
count = 0;
}
}
result.sort(function(a, b) {
if (a.count < b.count) return 1;
if (a.count > b.count) return -1;
return 0;
});
console.log(result.map(function(item){return item.value}));