How to merge two arrays in JavaScript loop - javascript

Is there a better way to do this? Faster or more readable? Please share your approach.
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
// expected output [0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]

You could iterate the array by the minimum of both array lengths and take the rest by slicing the arrays from the minimum length.
function merge(a, b) {
const
result = [];
l = Math.min(a.length, b.length);
for (let i = 0; i < l; i++) result.push(a[i], b[i]);
result.push(...a.slice(l), ...b.slice(l));
return result;
}
console.log(...merge([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], ['a', 'b', 'c', 'd', 'e', 'f']));

You can use either recursion:
const Nil =
Symbol();
const intercalate =
([x=Nil, ...xn], [y=Nil, ...yn], ret=[]) =>
x === Nil && y === Nil
? ret
: intercalate(xn, yn, ret.concat( x === Nil ? [] : x
, y === Nil ? [] : y
));
Or Array#flatMap:
const intercalate =
(xn, yn) =>
xn.flatMap((x, i) =>
i >= yn.length
? [x]
: [x, yn[i]]);

My approach:
function mergeBetween(a, b) {
let i = 0
let j = 1
while (true) {
const item = b[i]
if (!item) break
a.splice(j, 0, item)
j += 2
i++
}
return a
}
const a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
const b = [ 'a', 'b', 'c', 'd', 'e', 'f' ]
mergeBetween(a, b) //[0, 'a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 6, 7, 8, 9]

This would be my approach, if speed is your game, then you should stick to for loops... But I would suggest avoiding premature optimization in general... Not sure if that is what you meant by "faster" either...
const a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const b = ["a", "b", "c", "d", "e", "f"];
// check which is longer
const longer = a.length > b.length ? a : b;
const shorter = a.length < b.length ? a : b;
// declare a new variable to hold the combined array
let newArray = [];
for (let i = 0; i < longer.length; i++)
newArray =
i < shorter.length
? [...newArray, longer[i], shorter[i]]
: [...newArray, longer[i]];
console.log(newArray)

Related

how to find duplicate strings in array (['a', 'a', 'aa', 'a', 'aa'])

I am learning JS, and I have homework. I am asked to transform array into new array where each item is represented by the running count of element appearances.
For example
[1, 2, 1, 1, 3]
becomes
[1, 1, 2, 3, 1]
I wrote a code which works for numbers, but fails tests with strings:
UPDATE: IT works for some numbers, for others does not :/
function duplicates(arr) {
let i, j, newArr = [],
count = 1;
for (i = 0; i < arr.length; i++) {
for (j = 0; j < arr.length; j++) {
if (i == j) {
continue
}
if (arr[i] === arr[j]) {
newArr.push(count++)
break
}
}
if (j === arr.length) {
newArr.push(1)
}
}
return newArr
}
console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2] <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5] <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ] <-- MY CODE WORKS
Can you give me a hint? :/
Thank you!
One approach is to use .map(), .slice() and .filter()
const duplicates = (nums) =>
nums.map((value, index) => {
const segment = nums.slice(0,index+1);
return segment.filter(v => v === value).length;
});
console.log(duplicates([1, 2, 1, 1, 3]));
console.log(duplicates([1, 2, 1, 2, 3, 1]));
console.log(duplicates(['a', 'a', 'aa', 'a', 'aa']));
map creates a new array by iterating through nums and transforming each value via a function
slice is used to create a new array based on nums. In first example, the new array is [1] in first iteration, [1,2] in second, followed by [1,2,1] and so on.
filter finds the items in the array from #2 that match the current value.
Elaborating on #CRice and #Kaiido idea, let's create an object that is creating the count of the items while you're looping through the array:
function duplicates(arr) {
const obj = {};
let value = 0;
let newArr = [];
for (i = 0; i < arr.length; i++) {
value = arr[i];
if (obj[value]){
obj[value] = obj[value] + 1;
}
else{
obj[value] = 1;
}
newArr.push(obj[value]);
}
return newArr
}
console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2] <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5] <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ] <-- MY CODE WORKS
JS has a nice built-in, reduce, that does so in a simpler way:
const duplicates = (arr) => {
const obj = {}
return arr.reduce ( (acc,cur) => {
obj[cur] = (obj[cur])?obj[cur]+1:1
acc.push(obj[cur])
return acc
}, []);
}
console.log(duplicates(['a', 'a', 'aa', 'a', 'aa'])) //[ 1, 2, 1, 3, 2] <-- FAILS
console.log(duplicates([1, 2, 1, 2, 3, 1])) //[1, 2, 3, 4, 1, 5] <-- fails
console.log(duplicates([1, 2, 1, 1, 3])) //[ 1, 1, 2, 3, 2, 1 ] <-- MY CODE WORKS

How to concat arrays alternatively every 2 items? JS

I have:
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
array2 = ['a', 'b', 'c'];
I got the concat of arrays working, but only one at a time:
var alternatingArrayResult = [array1, array2].reduce(function (r, a) {
return a.forEach(function (a, i) {
return (r[i] = r[i] || []).push(a);
}), r;
}, []).reduce(function (a, b) {
return a.concat(b);
});
// => alternatingArrayResult = [1, 'a', 2, 'b', 3, 'c', 4, 5, 6, 7, 8, 9];
I want to add two items from array 1, then one from array 2 - and so on.
Desired output:
result = [1, 2, 'a', 3, 4, 'b', 5, 6, 'c', 7, 8, 9];
var array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array2 = ['a', 'b', 'c'];
var alternatingResultArray = [array1, array2].reduce(function (r, a) {
return a.forEach(function (a, i) {
return (r[i] = r[i] || []).push(a);
}), r;
}, []).reduce(function (a, b) {
return a.concat(b);
});
console.log(alternatingResultArray);
You could get a lenght and iterate the parts for pushing.
const
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
array2 = ['a', 'b', 'c'],
result = [];
for (i = 0, l = Math.max(Math.ceil(array1.length / 2), array2.length); i < l; i++) {
result.push(
...array1.slice(i * 2, (i + 1) * 2),
...array2.slice(i, i + 1),
);
}
console.log(...result);
A more abstact version with size of the wanted subarrays.
const
array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
array2 = ['a', 'b', 'c'],
data = [array1, array2],
sizes = [2, 1]
result = [];
for (i = 0, l = Math.max(...data.map(({ length }, i) => Math.ceil(length / sizes[i]))); i < l; i++) {
data.forEach((a, j) => result.push(...a.slice(i * sizes[j], (i + 1) * sizes[j])));
}
console.log(...result);
Use Array.map with a thisArg for the desired result (see MDN).
thisArg (Optional) Value to use as this when executing callback.
let array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let array2 = ['a', 'b', 'c'];
let arrayConcatted = array1
.flatMap( function(v, i) {
// ^ not arrow to keep thisArg in scope
const arr2Value = i && i % 2 === 0 && this.length && this.shift();
return arr2Value ? [arr2Value, v] : v;
}, array2.slice())
// ^ 'this', a copy of array2
console.log(JSON.stringify(arrayConcatted));
// IE
var arrConcatIE = [];
var arr2Clone = array2.slice();
for (var i=0; i < array1.length; i +=1) {
const arr2Value = i && i % 2 === 0 && arr2Clone.length && arr2Clone.shift();
if (arr2Value) {
arrConcatIE.push(arr2Value);
}
arrConcatIE.push(array1[i]);
}
console.log(JSON.stringify(arrConcatIE));

How to returns an object which shows the total number of occurences of each unique values?

Hi and I'm new to JavaScripts and hopefully anyone of you would help me to figure out. Thanks
My question is how to write a function that expects an array which could contain strings and/or numbers (as well as finite levels of nested arrays of strings and/or numbers), and returns an object which shows the total number of occurences of each unique values.
function functionName() {
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const outputResult = functionName(inputArray);
}
The key in the object is the unique values found in the array, and the value for each key is the number of occurences for each unique key
The expected result I want is :
{
'2': 4,
'5': 3,
'a': 1,
'd': 2,
'b': 2,
'1': 1,
'0': 1,
'A': 1,
}
You can try:
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const result = inputArray.flat(Infinity).reduce((acc, item) => (acc[item] = (acc[item] || 0) + 1, acc), {})
console.log(result)
You need to recursiely get occurences of each value, like implemented in calculateOccurences:
const calculateOccurences = function(inputArray, outputResult){
inputArray.forEach(function(value){
if(typeof(value)==='number' || typeof(value)==='string'){
outputResult[value] = outputResult[value] ? outputResult[value]+1 : 1;
}else if (Array.isArray(value)){
calculateOccurences(value, outputResult);
}
})
}
const inputArray = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
const outputResult = {}
calculateOccurences(inputArray, outputResult );
console.log(outputResult);
Assuming that numbers would be present in type number and not string or that 2 and '2' should be treated the same while calulating occurences.
In this case it's easier if you convert array into string.
var input = [ 2, 5, 2, 'a', [ 'd', 5, 2, ['b', 1], 0 ], 'A', 5, 'b', 2, 'd' ];
//conver intput into string and replace ',' characters
var stringInput = input.toString().replace(/,/g,'');
var output = {};
//counting
for (var i = 0; i < stringInput.length; i++) {
var element = stringInput[i];
output[element] = output[element] ? output[element] + 1 : 1;
}
console.log(output);

Have two javascipt arrays to combine into one object and add up values

I want to combine the following two same-size arrays:
var depts = [ 'A', 'D', 'M', 'G', 'D', 'B', 'D', 'A', 'A' ];
var cnts = [ 3, 7, 15, 2, 9, 5, 12, 4, 8 ];
Into an object like this, note cnts are the totals for each depts:
{A: 15, D: 19, M: 15, G: 2, B: 5}
Normally I perform data manipulation prior to web site integration however I want begin performing it in JavaScript. Some code that roughly mimics what I'm trying to do.
var obj = {};
for(var i = 0; i < depts.length; i++)
{
console.log(depts[i], cnts[i]);
obj[depts[i]] = cnts[i]; // <- don't know how to increment assignment
}
console.log(obj);
This code creates an object however does not sum cnts by depts:
{A: 8, D: 12, M: 15, G: 2, B: 5}
Just add a check if the property exist and assign zero. Later add the value to it.
var depts = ['A', 'D', 'M', 'G', 'D', 'B', 'D', 'A', 'A'],
cnts = [3, 7, 15, 2, 9, 5, 12, 4, 8],
obj = {};
for (var i = 0; i < depts.length; i++) {
if (!obj[depts[i]]) obj[depts[i]] = 0; // use an initial value
obj[depts[i]] += cnts[i]; // add value
}
console.log(obj);
Try this
const depts = [ 'A', 'D', 'M', 'G', 'D', 'B', 'D', 'A', 'A' ];
const cnts = [ 3, 7, 15, 2, 9, 5, 12, 4, 8 ];
let obj = {};
// loop over the first array, if not already in obj, put a zero before adding
depts.forEach((dept,i) => obj[dept] = (obj[dept] || 0) + cnts[i])
console.log(obj);
var depts = [ 'A', 'D', 'M', 'G', 'D', 'B', 'D', 'A', 'A' ];
var cnts = [ 3, 7, 15, 2, 9, 5, 12, 4, 8 ];
const lkp = depts.reduce((lkp, cur, i) => {
return {
...lkp,
[cur]: ~~lkp[cur] + cnts[i]
}
}, {})
console.log (lkp)

Is there a Javascript function similar to the Python Counter function?

I am attempting to change a program of mine from Python to Javascript and I was wondering if there was a JS function like the Counter function from the collections module in Python.
Syntax for Counter
from collection import Counter
list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a']
counter = Counter(list)
print counter
output
Counter({'a':5, 'b':3, 'c':2})
DIY JavaScript solution:
var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
function Counter(array) {
var count = {};
array.forEach(val => count[val] = (count[val] || 0) + 1);
return count;
}
console.log(Counter(list));
JSFiddle example
Update:
Alternative that uses a constructor function:
var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
function Counter(array) {
array.forEach(val => this[val] = (this[val] || 0) + 1);
}
console.log(new Counter(list));
JSFiddle example
You can use Lo-Dash's countBy function:
var list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
console.log(_.countBy(list));
JSFiddle example
I know I'm late but in case if someone is looking at this in 2020 you can do it using reduce, for example:
const counter = (list) => {
return list.reduce(
(prev, curr) => ({
...prev,
[curr]: 1 + (prev[curr] || 0),
}),
{}
);
};
console.log(counter([1, 2, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 1, 0]));
// output -> { '0': 1, '1': 6, '2': 2, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1 }
more advance example with a callback function and context binding
const data = [1, 2, 3, 4, 5];
const counter = (list, fun, context) => {
fun = context ? fun.bind(context) : fun;
return list.reduce((prev, curr) => {
const key = fun(curr);
return {
...prev,
[key]: 1 + (prev[key] || 0),
};
}, {});
};
console.log(counter(data, (num) => (num % 2 == 0 ? 'even' : 'odd')));
// output -> { odd: 3, even: 2 }
There is also pycollections.js, which works on Node and in client-side JS.
Example:
var collections = require('pycollections');
var counter = new collections.Counter([true, true, 'true', 1, 1, 1]);
counter.mostCommon(); // logs [[1, 3], [true, 2], ['true', 1]]
For those who want a pure JavaScript solution:
function countBy (data, keyGetter) {
var keyResolver = {
'function': function (d) { return keyGetter(d); },
'string': function(d) { return d[keyGetter]; },
'undefined': function (d) { return d; }
};
var result = {};
data.forEach(function (d) {
var keyGetterType = typeof keyGetter;
var key = keyResolver[keyGetterType](d);
if (result.hasOwnProperty(key)) {
result[key] += 1;
} else {
result[key] = 1;
}
});
return result;
}
Therefore:
list1 = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
console.log(countBy(list1)); // {'a':5, 'b':3, 'c':2}
list2 = ['abc', 'aa', 'b3', 'abcd', 'cd'];
console.log(countBy(list2, 'length')); // {2: 3, 3: 1, 4: 1}
list3 = [1.2, 7.8, 1.9];
console.log(countBy(list3, Math.floor)); // {1: 2, 7: 1}
In Python, the Counter also has add and update methods, which are used quite commonly. So a better solution would be this:
function Counter(array) {
this.add = (val) => {
this[val] = (this[val] || 0) + 1;
};
this.update = (array) => {
array.forEach((val) => this.add(val));
};
this.update(array);
}
// Example usage
let myCounter = new Counter([1, 2, 2])
myCounter.update([3, 3, 3])
myCounter.add(4)
console.log(myCounter)
Here is a simple and easy to read solution:
const word1 = "tangram"
const dict1 = {}
for (let char of word1){
console.log(char)
if (dict1[char]){
dict1[char] += 1
}else{
dict1[char]= 1
}
}
This is my solution with explicit function calls
let list = [4, 6, 5, 3, 3, 1];
function counter(list) {
let count = function(n) {
let cnt = 0;
for (let v of list) {
if (v === n) cnt++
}
return cnt
}
let [...listSet] = new Set(list);
let cntr = {};
for (let v of listSet) {
cntr[v] = count(v)
}
return cntr
}
console.log(counter(list))
Another version ->
s = "naman";
const counter = (s, sMap = {}) => {
[...s].map((el) => {
sMap[el] = sMap[el] ? sMap[el] + 1 : 1;
});
return sMap;
};
const res = counter(s);
console.log(`res`, res);
How about this pure functional way:
let list = ['a', 'b', 'c', 'b', 'a', 'b', 'c', 'a', 'a', 'a'];
function counter(array) {
return array.reduce((acc, value, index) => {
acc[value] = value in acc ? acc[value] + 1: 1
return acc;
}, {});
}
Fiddle Link

Categories