I have a little question about joining arrays. I have an array of letters, something like that:
let array = ['a','b','','c']
I wan't to join elements in array to have output like that:
let array = ['ab','c']
Can you help me? I was searching but everything i found was about removing whitespaces from arrays or string :(
Something along these lines:
let array = ['a', 'b', '', 'c'];
let res = array.reduce((res, s) => {
if (s.length) {
res[res.length - 1] += s;
} else {
res.push('');
}
return res;
}, ['']);
console.log(res);
It does make the assumption that there will be at least one string in the array, that the last element won't be an empty string and that there won't be two adjacent empty strings. Adjust as necessary if those are concerns.
You can use a combination of Array#map, Array#join and String#Split to achieve what you want.
Here, I used a space as the delimiter, but you can use anything that you don't use in your array.
let array = ['a','b','','c'];
let result = array.map(e => e.length ? e : ' ').join('').split(' ');
console.log(result);
You could use reduce() method to create new array and one variable to increment on empty string.
let array = ['a', 'b', '', 'c', 'd', 'e', '', '', '', 'f', '', 'g'];
let i = 0;
let result = array.reduce((r, e, j, arr) => {
r[i] = (r[i] || '') + e;
if (!e && arr[j - 1]) i++
return r;
}, [])
console.log(result)
Related
Currently I am looping through an array of letters, after each click a letter will be added. And there is also a string (var word) that will randomly be chosen, and the expected result is that it have to return true each time when there is an unmatching letter being added to the 'currentArray'. So after each click on an unmatched letter this function should still work!
For example if currentArray = ['b', 'o', 'l']
word is 'bob'. It should return true once....
I tried this one before, but as you might know this is the wrong way -->
currentArray.filter((word) => word !== word)
If I understand you correctly, the following code will help you.
let currentArray = ['b', 'o', 'l'];
let pattern = "bob";
let notIncluded = currentArray.filter(char => pattern.indexOf(char) === -1);
console.log(notIncluded);
Here's a one-liner that should do the trick.
const arr = ['b', 'o', 'l'];
const arr2 = ['b', 'o']
const word = 'bob';
let out = arr.filter(el => word.split('').indexOf(el) === -1).length > 0;
let out2 = arr2.filter(el => word.split('').indexOf(el) === -1).length > 0;
console.log(out, out2)
You're essentially filtering out elements of the array if a letter from the word is present, then check if the length is greater than 0.
I think this is what you were requesting.
I'm trying to double each element in an array
let arr = ['onions', 'tomatoes', 'etc'...';
with a for loop and keep getting NaN error... I'm still learning so any advice would be appreciated.
I've tried for loop, .map(), and other methods, but just can't see the obvious problem...
let newIngr = tortSoup.filter(function(value, index, arr) {
if (value !== 'onion' && value !== 'red pepper') {
return value;
console.log(newIngr);
});
}
let myReci = [];
for(var i = 0; i < newIngr.length; i++) {
myReci[i] = newIngr[i] * 2;
}
console.log(myReci);
Expected: each array element multiped by two and returned:
['onions', tomatoes', 'garlic', 'fontina']
would become:
['onions', 'onions', 'tomoatoes', 'tomatoes', garlic, 'garlic', 'fontina', 'fontina']
Here is a way to do it with Array.reduce() and the spread operator:
const array = ['onions', 'tomatoes', 'garlic', 'fontina'];
const result = array.reduce((acc, x) => ([...acc, x, x]), []);
console.log(result)
Array.reduce iterates over your input array and calls the callback for each element. This callback is given two arguments, the first is the output from the last iteration, and the second one is the current array item.
The callback here returns a new array composed of the previous result of the callback (spread into the new array with the spread operator ...) and the current item repeated twice.
To start the reducing process, we also need an initial value, here we give an empty array, (last argument to reduce).
Here is a detailed description of the values of acc and x in the callback for the following reduction:
['a', 'b', 'c'].reduce((acc, x) => ([...acc, x, x]), []);
acc = [], x = 'a' => returns ['a', 'a']
acc = ['a', 'a'], x = 'b' => returns ['a', 'a', 'b', 'b']
acc = ['a', 'a', 'b', 'b'], x = 'c' => returns ['a', 'a', 'b', 'b', 'c', 'c']
Iterate over input array using .map().
Initialize new array using Array() constructor and filling it using .fill() method of arrays.
Finally you can convert array of arrays to a single array using .concat() and spread operator.
const input = ['onions', 'tomatoes', 'garlic', 'fontina'];
const dupeValues = (arr, factor) => [].concat(...arr.map(s => new Array(factor).fill(s)));
console.log(dupeValues(input, 2));
console.log(dupeValues(input, 3));
Use Array.flatMap() (not supported by IE/Edge):
const array = ['onions', 'tomatoes', 'garlic', 'fontina'];
const result = array.flatMap(item => [item, item]);
console.log(result)
Using vanilla JavaScript :
const ingredients = [ 'onions', 'tomatoes', 'garlic', 'fontina' ]
const ingredientsToRemove = [ 'onions', 'red pepper' ]
// Using Array.reduce method
const doubleIngredients = ingredients.reduce(
( array, ingredient ) =>
{
// If the ingredient has to be removed, return the array
// Else return the array with two times the current ingredient
return ingredientsToRemove.includes( ingredient ) ?
array
:
[ ...array, ingredient, ingredient ]
},
[]
)
console.log({ ingredients, doubleIngredients })
Well the problem here is
string * 2 will not return 2 strings to you. it will return NaN
console.log('test'* 2) //NaN
What you're trying to achieve can be done by repeat method.
console.log('test '.repeat(2))
Your expected output can be achieved like this
let arr = ['onions', 'tomatoes', 'garlic', 'fontina']
let output = arr.reduce((op,inp)=>(op.concat([inp,inp])),[])
console.log(output)
I have an array of characters (arr) and a string (J), I wanted to use the array.reduce() method to count the number of characters of the array (arr) present in the string J.
Below is the code which shows how I am using array.reduce() method,
let val = arr.reduce((count , ch) => {
return J.includes(ch) ? count + 1 : count
});
But when I tried with sample value as,
arr = [ 'a', 'A', 'A', 'S', 'S' ];
J = 'aA';
I get the anser as
val = 'a11'
You need to add initialValue in second parameter of .reduce() as mentioned in docs
arr.reduce(callback[, initialValue])
var arr = [ 'a', 'A', 'A', 'S', 'S' ];
var J = 'aA';
let val = arr.reduce((count , ch) => {
return J.includes(ch) ? count + 1 : count
}, 0);
console.log(val);
i would like to split an array into multiple chunks but applying a function to it to decide how to create the chunks.
For example, if i have an array of letters, numbers or letters and numbers, apply a function to the array to split it into array of arrays of the previous categories.
let arr = ['a', 'b', '1', '2', 'a1', 'a2', 'c', '3', 'a3']
myChunkFunction(arr, myCustomSplitFunction)
// result
[['a','b','c'], ['1','2','3'], ['a1', 'a2','a3']]
Lodash has a chunk function but it splits into n chunks, also array has a slice function but you need to specify the begin and the end so how could i split with a custom function.
Try doing this
let arr = ['a', 'b', '1', '2', 'a1', 'a2', 'c', '3', 'a3']
const splitFn = (str) => Number.isInteger(+str) ? 0 : str.length == 1 ? 1 : 2
const myChunkFunction = (arr, fn) => arr.reduce((r,c) => {
let t = fn(c)
r[t] = [...r[t], c]
return r
}, [[],[],[]])
console.log(myChunkFunction(arr, splitFn))
Hint
The key to the answer is to, somehow, reorganize the source array such that all the elements with the same key will be in the same place.
The easiest way I can think to solve it is by using hash-map. Each element in the hash-map will be a different array containing all the elements with the same key.
Try it for your self before you keep reading and see the full solution.
The implementation
As you can see, I solved it as functional as possible. To avoid mutations, I used reduce to iterate over the source array and put each element in the hashmap (by generating a key from the element).
I recreate the final hash-map over and over using shallow copy. Finally, I convert the hash-map to an array of array (because that was your demand) using Object.values
const splitArrayByKey = extractKey => array => {
const arraysByKey_obj = array.reduce((hashMapOfArrays,element)=> {
const key = extractKey(element);
// if we already added an element with the same key,
// then we add the current element to there.
// else, we create a new key and put the current element there.
if(hashMapOfArrays.hasOwnProperty(key))
return {
...hashMapOfArrays,
[key]: [...hashMapOfArrays[key],element]
};
return {
...hashMapOfArrays,
[key]: [element]
};
},{});
// transform the arraysByKey_obj to an array of arrays:
return Object.values(arraysByKey_obj);
};
// example 1:
const result1 = splitArrayByKey(element=>element)([1,2,3,1,2,3]);
console.log(result1);
console.log('------------------');
// example 2:
const result2 = splitArrayByKey(element=>element.id)([{id:1,x:1},{id:{},x:2},{id:"id",x:3},{id:1,x:4}]);
console.log(result2);
Here is a way to do this via ES6:
let arr = ['a', 'b', '1', '2', 'a1', 'a2', 'c', '3', 'a3']
const splitFn = (str) => Number.isInteger(+str) ? 0 : str.length == 1 ? 1 : 2
const myChunkFunction = (arr, fn) => arr.reduce((r,c) => {
let t = fn(c)
r[t] = [...r[t], c]
return r
}, [[],[],[]])
console.log(myChunkFunction(arr, splitFn))
The typeFn plays the role of filtering the elements to number, string with 1 length and other. That output is used by the myChunkFunction to place the element in the right array.
You could do something like this with less control and in one line with reduce and ES6 array spread:
let arr = ['a', 'b', '1', '2', 'a1', 'a2', 'c', '3', 'a3']
const result = arr.reduce((r,c) =>
(Number.isInteger(+c) ? r[0] = [...r[0], c] :
c.length == 1 ? r[1] = [...r[1], c] : r[2] = [...r[2], c], r), [[],[],[]])
console.log(result)
You start with [[],[],[]] and fill each of the sub arrays based on number, length of the string == 1, other lenghts.
You could wrap that in a function.
const arr = ['a', 'b', '1', '2', 'a1', 'a2', 'c', '3', 'a3'];
const getClassification = function(x){
const hasNumber = x.split('').some(x => parseFloat(x));
const hasChar = x.split('').some(x => !parseFloat(x));
if(!parseFloat(x) && (!hasNumber && hasChar)) return 0;
else if(parseFloat(x)) return 1;
else return 2;
}
const myChunkFunction = function(arr, classifier){
let jaggedArray = [[], [], []];
arr.forEach(x => {
jaggedArray[classifier(x)].push(x);
})
return jaggedArray;
}
console.log(myChunkFunction(arr, getClassification));
I think this satisfies.
I want to split an array of strings into two arrays.
However, when I push the strings into the new arrays, it should be alternating. So, if the array is:
let alph = [a,b,c,d,e,f]
Then the new arrays would look like:
firstArr = [a,c,e]
secondArr = [b,d,f]
How can I do it so I'm not repeating myself? I have the following code, and it works, but I do not want to write two of the same filter functions (keep things DRY):
let firstArr = alph.filter((letter, index) => {
return index % 2 === 0;
})
You could take an array of the both arrays and take the index as indicator for the wanted array for pushing.
let alph = ['a', 'b', 'c', 'd', 'e', 'f'],
first = [],
second = [],
temp = [first, second];
alph.forEach((v, i) => temp[i % 2].push(v));
console.log(first);
console.log(second);
Since filter creates one array, you need two, or use e.g. forEach
var arr = ["a","b","c","d","e","f"], firstArr = [], secondArr = [];
arr.forEach( (a,i) => {
(i % 2 === 0) ? firstArr.push(a) : secondArr.push(a);
})
console.log(firstArr)
console.log(secondArr)
For better readability there's nothing wrong with having separate filter functions for these. To clean it up a little you could use arrow functions and make them 1 liners and then pass them in the filter function, like:
const alpha = ['a', 'b', 'c', 'd', 'e', 'f'];
const filterByEvens = (letter, index) => index % 2 === 0;
const filterByOdds = (letter, index) => index % 2 !== 0;
const evens = alpha.filter(filterByEvens);
const odds = alpha.filter(filterByOdds);
you can use reduce for this :
const alph = ['a', 'b', 'c', 'd', 'e', 'f'];
const result = alph.reduce((acc, letter, ndx) => {
acc[ndx % 2] = acc[ndx % 2] || [];
acc[ndx % 2].push(letter);
return acc;
}, []);
const [firstArr, secondArr] = result;
console.log(firstArr, secondArr);