Use array.reduce() for array of characters - javascript

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);

Related

Grouping same values from JavaScript array [duplicate]

This question already has answers here:
How to count duplicate value in an array in javascript
(35 answers)
Closed 4 years ago.
let array = ['a', 'a', 'a', 'b', 'b', 'c'];
i want to group double values from array, to get result like this:
result:
['3a, 2b, c']
(or something similar)
Any idea?
You can use .reduce() and .map() methods:
let array = ['a', 'a', 'a', 'b', 'b', 'c'];
let result = Object.entries(
array.reduce((r, c) => (r[c] = (r[c] || 0) + 1, r) , {})
).map(([k, v]) => v == 1 ? k : v + k);
console.log(result);
You can also use Map if you need items in specific order:
let array = ['a', 'a', 'a', 'b', 'b', 'c'];
let result = (((arr, map) => {
arr.forEach(s => map.set(s, (map.get(s) || 0) + 1));
return [...map.entries()].map(([k, v]) => v == 1 ? k : v + k);
})(array, new Map()));
console.log(result);
I would recommend using a dictionary to track the duplicate values in the array.
var dictionary = {};
for(var i = 0;i < array.length;i++){
var value = array[i];
if(dictionary[value] === undefined){
dictionary[value] = 0;
}
dictionary[value] = dictionary[value] + 1;
}
console.log(dictionary)
function count() {
array_elements = ["a", "b", "c", "d", "e", "a", "b", "c", "f", "g", "h", "h", "h", "e", "a"];
array_elements.sort();
var current_elements = null;
var count= 0;
for (var i = 0; i < array_elements.length; i++) {
if (array_elements[i] != current_elements) {
if (cnt > 0) {
console.log(current_elements+count);
}
current_elements= array_elements[i];
count= 1;
} else {
count++;
}
}
if (cnt > 0) {
console.log(current_elements+count);
}
}
A single loop approach for simple run-length encoding (RLE) function.
let array = ['a', 'a', 'a', 'b', 'b', 'c'],
result = array.reduce(
(r, c, i, a) => r.concat(c === a[i - 1]
? ((+r.pop().slice(0, -1) || 1) + 1) + c
: c),
[]
);
console.log(result);
You can use Array.reduce() to produce an object with key-value (array value and count) pairs, then Array.map() to produce an array using Object.keys().
let array = ['a', 'a', 'a', 'b', 'b', 'c'];
let countObj = array.reduce((acc, val) => (acc[val] = acc[val] ? acc[val] + 1 : 1, acc), {});
console.log(countObj);
let countArr = Object.keys(countObj).map(key => '' + countObj[key] + key);
console.log(countArr);
For "something similar" why not just have an object that maps letter to occurrence. You can then simply use dot notation to get the property value assigned to each key.
Here I've used reduce.
const arr = ['a', 'a', 'a', 'b', 'b', 'c'];
// `reduce` over the arr
const obj = arr.reduce((acc, c) => {
// If the object (acc) we passed in doesn't have
// a key assigned to the letter in the current
// iteration (c) add it, set it to 0, then
// add one, otherwise, if there is a key, add one
acc[c] = (acc[c] || 0) + 1;
// Return the object for the next iteration
return acc;
// Pass in an initial object
}, {});
console.log(obj);
// Grab the value of `a` property
console.log(obj.a);

How can I split an array into two arrays with alternating elements

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);

Join array without removing whitespace

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)

Basic JavaScript associative array

I have an array of items.
var items = {'A', 'A', 'A', 'B', 'B', 'C'}
I want to output an array that counts how many of each item there is.
So the output should look like:
{
'A': 3,
'B': 2,
'C': 1
}
The biggest reason why it isn't working is that using {} means that you are declaring an object, using [] means you are declaring an array.
Other than that, the code you wrote requires very little modification
var items = ['A', 'A', 'A', 'B', 'B', 'C'];
function count(items) {
var result = [];
var count = 0;
for (var i=0; i<items.length; i++) {
var item = items[i];
if(typeof result[item] === 'undefined') {
//this is the first time we have encountered this key
//so we initialize its count to 0
result[item] = 0;
}
result[item]++;
}
return result;
}
var result = count(items);
for (var key in result) {
alert(key + " : " + result[key]);
}
If you have an array [] instead of an object {} this works:
var items = ['A', 'A', 'A', 'B', 'B', 'C'];
var o = {};
items.forEach(function(element) {
(element in o) ? o[element]++ : o[element] = 1;
});
If you have a real object with keys and values you could use Object.keys() on items to return an array.

Javascript - sort array based on another array

Is it possible to sort and rearrange an array that looks like this:
itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
to match the arrangement of this array:
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Unfortunately, I don’t have any IDs to keep track on. I would need to priority the items-array to match the sortingArr as close as possible.
Update:
Here is the output I’m looking for:
itemsArray = [
['Bob', 'b'],
['Jason', 'c'],
['Henry', 'b'],
['Thomas', 'b']
['Anne', 'a'],
['Andrew', 'd'],
]
Any idea how this can be done?
One-Line answer.
itemsArray.sort(function(a, b){
return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});
Or even shorter:
itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));
Something like:
items = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && item[1] == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})
Here's a shorter code, but it destroys the sorting array:
result = items.map(function(item) {
var n = sorting.indexOf(item[1]);
sorting[n] = '';
return [n, item]
}).sort().map(function(j) { return j[1] })
If you use the native array sort function, you can pass in a custom comparator to be used when sorting the array. The comparator should return a negative number if the first value is less than the second, zero if they're equal, and a positive number if the first value is greater.
So if I understand the example you're giving correctly, you could do something like:
function sortFunc(a, b) {
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}
itemsArray.sort(sortFunc);
Case 1: Original Question (No Libraries)
Plenty of other answers that work. :)
Case 2: Original Question (Lodash.js or Underscore.js)
var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });
Case 3: Sort Array1 as if it were Array2
I'm guessing that most people came here looking for an equivalent to PHP's array_multisort (I did) so I thought I'd post that answer as well. There are a couple options:
1. There's an existing JS implementation of array_multisort(). Thanks to #Adnan for pointing it out in the comments. It is pretty large, though.
2. Write your own. (JSFiddle demo)
function refSort (targetData, refData) {
// Create an array of indices [0, 1, 2, ...N].
var indices = Object.keys(refData);
// Sort array of indices according to the reference data.
indices.sort(function(indexA, indexB) {
if (refData[indexA] < refData[indexB]) {
return -1;
} else if (refData[indexA] > refData[indexB]) {
return 1;
}
return 0;
});
// Map array of indices to corresponding values of the target array.
return indices.map(function(index) {
return targetData[index];
});
}
3. Lodash.js or Underscore.js (both popular, smaller libraries that focus on performance) offer helper functions that allow you to do this:
var result = _.chain(sortArray)
.pairs()
.sortBy(1)
.map(function (i) { return itemArray[i[0]]; })
.value();
...Which will (1) group the sortArray into [index, value] pairs, (2) sort them by the value (you can also provide a callback here), (3) replace each of the pairs with the item from the itemArray at the index the pair originated from.
this is probably too late but, you could also use some modified version of the code below in ES6 style. This code is for arrays like:
var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];
The actual operation :
arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));
The actual operation in ES5 :
arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
return arrayToBeSorted.includes(v);
});
Should result in arrayToBeSorted = [3,5]
Does not destroy the reference array.
function sortFunc(a, b) {
var sortingArr = ["A", "B", "C"];
return sortingArr.indexOf(a.type) - sortingArr.indexOf(b.type);
}
const itemsArray = [
{
type: "A",
},
{
type: "C",
},
{
type: "B",
},
];
console.log(itemsArray);
itemsArray.sort(sortFunc);
console.log(itemsArray);
Why not something like
//array1: array of elements to be sorted
//array2: array with the indexes
array1 = array2.map((object, i) => array1[object]);
The map function may not be available on all versions of Javascript
ES6
const arrayMap = itemsArray.reduce(
(accumulator, currentValue) => ({
...accumulator,
[currentValue[1]]: currentValue,
}),
{}
);
const result = sortingArr.map(key => arrayMap[key]);
More examples with different input arrays
I would use an intermediary object (itemsMap), thus avoiding quadratic complexity:
function createItemsMap(itemsArray) { // {"a": ["Anne"], "b": ["Bob", "Henry"], …}
var itemsMap = {};
for (var i = 0, item; (item = itemsArray[i]); ++i) {
(itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
}
return itemsMap;
}
function sortByKeys(itemsArray, sortingArr) {
var itemsMap = createItemsMap(itemsArray), result = [];
for (var i = 0; i < sortingArr.length; ++i) {
var key = sortingArr[i];
result.push([itemsMap[key].shift(), key]);
}
return result;
}
See http://jsfiddle.net/eUskE/
var sortedArray = [];
for(var i=0; i < sortingArr.length; i++) {
var found = false;
for(var j=0; j < itemsArray.length && !found; j++) {
if(itemsArray[j][1] == sortingArr[i]) {
sortedArray.push(itemsArray[j]);
itemsArray.splice(j,1);
found = true;
}
}
}
http://jsfiddle.net/s7b2P/
Resulting order: Bob,Jason,Henry,Thomas,Anne,Andrew
In case you get here needing to do this with an array of objects, here is an adaptation of #Durgpal Singh's awesome answer:
const itemsArray = [
{ name: 'Anne', id: 'a' },
{ name: 'Bob', id: 'b' },
{ name: 'Henry', id: 'b' },
{ name: 'Andrew', id: 'd' },
{ name: 'Jason', id: 'c' },
{ name: 'Thomas', id: 'b' }
]
const sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Object.keys(itemsArray).sort((a, b) => {
return sortingArr.indexOf(itemsArray[a].id) - sortingArr.indexOf(itemsArray[b].id);
})
let a = ['A', 'B', 'C' ]
let b = [3, 2, 1]
let c = [1.0, 5.0, 2.0]
// these array can be sorted by sorting order of b
const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]))
const sortBy = (a, b, c) => {
const zippedArray = zip([a, b, c])
const sortedZipped = zippedArray.sort((x, y) => x[1] - y[1])
return zip(sortedZipped)
}
sortBy(a, b, c)
For getting a new ordered array, you could take a Map and collect all items with the wanted key in an array and map the wanted ordered keys by taking sifted element of the wanted group.
var itemsArray = [['Anne', 'a'], ['Bob', 'b'], ['Henry', 'b'], ['Andrew', 'd'], ['Jason', 'c'], ['Thomas', 'b']],
sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ],
map = itemsArray.reduce((m, a) => m.set(a[1], (m.get(a[1]) || []).concat([a])), new Map),
result = sortingArr.map(k => (map.get(k) || []).shift());
console.log(result);
I hope that I am helping someone, but if you are trying to sort an array of objects by another array on the first array's key, for example, you want to sort this array of objects:
const foo = [
{name: 'currency-question', key: 'value'},
{name: 'phone-question', key: 'value'},
{name: 'date-question', key: 'value'},
{name: 'text-question', key: 'value'}
];
by this array:
const bar = ['text-question', 'phone-question', 'currency-question', 'date-question'];
you can do so by:
foo.sort((a, b) => bar.indexOf(a.name) - bar.indexOf(b.name));
This is what I was looking for and I did for sorting an Array of Arrays based on another Array:
It's On^3 and might not be the best practice(ES6)
function sortArray(arr, arr1){
return arr.map(item => {
let a = [];
for(let i=0; i< arr1.length; i++){
for (const el of item) {
if(el == arr1[i]){
a.push(el);
}
}
}
return a;
});
}
const arr1 = ['fname', 'city', 'name'];
const arr = [['fname', 'city', 'name'],
['fname', 'city', 'name', 'name', 'city','fname']];
console.log(sortArray(arr,arr1));
It might help someone
I had to do this for a JSON payload I receive from an API, but it wasn't in the order I wanted it.
Array to be the reference array, the one you want the second array sorted by:
var columns = [
{last_name: "last_name"},
{first_name: "first_name"},
{book_description: "book_description"},
{book_id: "book_id"},
{book_number: "book_number"},
{due_date: "due_date"},
{loaned_out: "loaned_out"}
];
I did these as objects because these will have other properties eventually.
Created array:
var referenceArray= [];
for (var key in columns) {
for (var j in columns[key]){
referenceArray.push(j);
}
}
Used this with result set from database. I don't know how efficient it is but with the few number of columns I used, it worked fine.
result.forEach((element, index, array) => {
var tr = document.createElement('tr');
for (var i = 0; i < referenceArray.length - 1; i++) {
var td = document.createElement('td');
td.innerHTML = element[referenceArray[i]];
tr.appendChild(td);
}
tableBody.appendChild(tr);
});
let sortedOrder = [ 'b', 'c', 'b', 'b' ]
let itemsArray = [
['Anne', 'a'],
['Bob', 'b'],
['Henry', 'b'],
['Andrew', 'd'],
['Jason', 'c'],
['Thomas', 'b']
]
a.itemsArray(function (a, b) {
let A = a[1]
let B = b[1]
if(A != undefined)
A = A.toLowerCase()
if(B != undefined)
B = B.toLowerCase()
let indA = sortedOrder.indexOf(A)
let indB = sortedOrder.indexOf(B)
if (indA == -1 )
indA = sortedOrder.length-1
if( indB == -1)
indB = sortedOrder.length-1
if (indA < indB ) {
return -1;
} else if (indA > indB) {
return 1;
}
return 0;
})
This solution will append the objects at the end if the sorting key is not present in reference array
const result = sortingArr.map((i) => {
const pos = itemsArray.findIndex(j => j[1] === i);
const item = itemsArray[pos];
itemsArray.splice(pos, 1);
return item;
});
this should works:
var i,search, itemsArraySorted = [];
while(sortingArr.length) {
search = sortingArr.shift();
for(i = 0; i<itemsArray.length; i++) {
if(itemsArray[i][1] == search) {
itemsArraySorted.push(itemsArray[i]);
break;
}
}
}
itemsArray = itemsArraySorted;
You could try this method.
const sortListByRanking = (rankingList, listToSort) => {
let result = []
for (let id of rankingList) {
for (let item of listToSort) {
if (item && item[1] === id) {
result.push(item)
}
}
}
return result
}
with numerical sortingArr:
itemsArray.sort(function(a, b){
return sortingArr[itemsArray.indexOf(a)] - sortingArr[itemsArray.indexOf(b)];
});
This seems to work for me:
var outputArray=['10','6','8','10','4','6','2','10','4','0','2','10','0'];
var template=['0','2','4','6','8','10'];
var temp=[];
for(i=0;i<template.length;i++) {
for(x=0;x<outputArray.length;x++){
if(template[i] == outputArray[x]) temp.push(outputArray[x])
};
}
outputArray = temp;
alert(outputArray)
Use the $.inArray() method from jQuery. You then could do something like this
var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
var newSortedArray = new Array();
for(var i=sortingArr.length; i--;) {
var foundIn = $.inArray(sortingArr[i], itemsArray);
newSortedArray.push(itemsArray[foundIn]);
}
Use intersection of two arrays.
Ex:
var sortArray = ['a', 'b', 'c', 'd', 'e'];
var arrayToBeSort = ['z', 's', 'b', 'e', 'a'];
_.intersection(sortArray, arrayToBeSort)
=> ['a', 'b', 'e']
if 'z and 's' are out of range of first array, append it at the end of result
this.arrToBeSorted = this.arrToBeSorted.sort(function(a, b){
return uppthis.sorrtingByArray.findIndex(x => x.Id == a.ByPramaeterSorted) - uppthis.sorrtingByArray.findIndex(x => x.Id == b.ByPramaeterSorted);
});
You can do something like this:
function getSorted(itemsArray , sortingArr ) {
var result = [];
for(var i=0; i<arr.length; i++) {
result[i] = arr[sortArr[i]];
}
return result;
}
You can test it out here.
Note: this assumes the arrays you pass in are equivalent in size, you'd need to add some additional checks if this may not be the case.
refer link
refer

Categories

Resources