Convert array of strings to hashmap with count javascript - javascript

Is there a better way to convert
["88 99", "20 99", "12 12"]
to a hashmap in the form
{"88": 1, "99": 2, "20": 1, "12": 1}
Using map or reduce?
Where in this case, a string with duplicate numbers only gets increases it's count by 1.
Currently I'm converting the above array into a 2d array using .split(' ')
and iterating over that 2d array in another for loop as so:
var counts = {}
for (let i = 0; i < logs.length; i++){
let ack = logs[i].split(' ');
if(ack[0]==ack[1]){
counts[ack[0]] = counts[ack[0]] ? counts[ack[0]] + 1 : 1;
}
else{
for(let j= 0; j < 2; j++){
counts[ack[j]] = counts[ack[j]] ? counts[ack[j]] + 1 : 1;
}
}
}

First I group by numbers, summing the appearances of each. This is using the reduce part. That's it. I used adaption of method by https://stackoverflow.com/a/62031473/3807365
var arr = ["88 99", "20 99", "12 12"]
var step1 = arr.reduce(function(agg, pair) {
pair.split(" ").forEach(function(item) {
agg[item] = (agg[item] || 0) + 1
})
return agg;
}, {})
console.log(step1)

Yes. I'm assuming you want to write in a functional style, so I'm not worrying about efficiency, etc.
You can collapse this into a hairy one-liner but I wrote the intermediate steps and output them for illustration.
const input = ["88 99", "20 99", "12 12"];
const split = input.map( (string) => string.split(" ") );
console.log("split: " + JSON.stringify(split));
const flattened = split.reduce( (acc,array) => acc = acc.concat(array), []);
console.log("flattened: " + JSON.stringify(flattened));
const output = flattened.reduce( (byKey, item) => {
if (!byKey[item]) byKey[item] = 0;
byKey[item]++;
return byKey;
}, {});
console.log(JSON.stringify(output))

Related

Getting wrong elements in an array after comparing two array values

I have two arrays villanStrength = [112,243,512,343,90,478] and playerStrength = [5,789,234,400,452,150] of same length, I am comparing each value of array playerStrength with villanStrength and forming up an another array which will store the either 0 or 1 (false or true) based on comparison, but the output array I am getting is not desirable. Please help me...
my code:
process.stdin.resume();
process.stdin.setEncoding('ascii');
var userInput = //providing this externally from the file
1
6
112 243 512 343 90 478
5 789 234 400 452 150;
var testCases = "";
var numberOfPlayers = "";
var villanStrength = [];
var playerStrength = [];
process.stdin.on('data', (data) => {
userInput = data;
// console.log("user input = " + userInput);
let res = userInput.split("\n");
testCases = res[0];
// for (i=1; i<=testCases; i++) {
numberOfPlayers = res[1];
// console.log("cases = " + testCases);
// console.log("number of players = " + numberOfPlayers);
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
console.log("villan Strength = " + villanStrength);
console.log("player Strength = " + playerStrength);
let isSmall = false;
let comparisonResult = [];
for (let j=0; j<villanStrength.length; j++) {
for (let k=0; k<playerStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[k] = 1; //true = 1, false = 0
} else {
comparisonResult[k] = 0;
}
}
console.log("comparison result for " + j +":" + comparisonResult);
if(comparisonResult.find((findOne) => {return findOne = 1;} )) {
isSmall = true;
console.log("LOSE");
break;
}
}
if (isSmall === false) {
console.log("Win");
}
// }
});
The output array is comparisonResult[] and the values inside comparisonResult I am getting is as below:
villan Strength = 112,243,512,343,90,478
player Strength = 5,789,234,400,452,150
comparison result for 0: 0,0,1,0,1,0 //this should be 1,1,1,1,1,1
comparison result for 1: 0,0,0,0,1,0
comparison result for 2: 0,1,1,1,1,1
comparison result for 3: 0,0,1,0,1,1
comparison result for 4: 0,0,1,0,1,1
comparison result for 5: 0,1,1,1,1,1
in the above result it is expected that the 'comparison result for 0' should be [1,1,1,1,1,1] but it is [0,0,1,0,1,0].
There are a couple problems with this code.
When you compare values in your arrays, you are comparing strings, not numbers. The values you get from stdin are text values, not numeric values. So, for example '5' > '100'. I presume this is the major source of your issue. If you want to do numeric comparisons, you need to convert the strings to numbers.
You are assuming that you get ALL your data on the first data event. While that may usually be true, it is not guaranteed and you should not rely on it when programming. You have to collect data in one or more data events until you have a full chunk of data you can process.
If you add these two log statements that show the actual contents of the array (not the .toString() conversion of the array):
console.log("villan strength: ", villanStrength);
console.log("player strength: ", playerStrength);
You will see this output:
villan strength: [ '112', '243', '512', '343', '90', '478\r' ]
player strength: [ '5', '789', '234', '400', '452', '150;\r' ]
Note, these are strings and when coming from my text file, there's a trailing \r too.
If you change this:
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
to this:
villanStrength = res[2].split(" ").map(item => parseInt(item.trim(), 10));
playerStrength = res[3].split(" ").map(item => parseInt(item.trim(), 10));
Then, it will trim off the newline and convert them to numbers and your comparisons will make sense. This is why the code you posted originally in your question did not generate the wrong output because you hacked in an array of numbers (for purposes of the original question), but your original code was ending up with an array of strings.
Based on your requirement, the playerStrength loop needs to be the outer loop and comparisonResult should be an array of arrays
villanStrength = [112,243,512,343,90,478]
playerStrength = [5,789,234,400,452,150]
// ...
let comparisonResult = []; //output array
for (let j=0; j< playerStrength.length; j++) {
comparisonResult[j] = [];
for (let k=0; k<villanStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[j].push(1); //true = 1, false = 0
} else {
comparisonResult[j].push(0);
}
}
console.log("comparison result for player " + j +":" + comparisonResult[j]);
}
If I understand the question right you need to compare each value from array1 to array2 and generate a new array that show diffrent...
All you need is just one loop that can take both values and push result of comparison to another array
function compare() {
const villanStrength = [112, 243, 512, 343, 90, 478];
const playerStrength = [5, 789, 234, 400, 452, 150];
const result = [];
for (let i = 0; i < villanStrength.length; i++) {
const vVal = villanStrength[i];
const pVal = playerStrength[i];
if (pVal < vVal) {
result.push(1);
continue;
}
result.push(0);
}
console.log(result);
}
My suggestion for is to separate codes to smaller funtions so you can focus on each section

Conditionally split and concat text

I am trying to conditionally split each of the string in an array.This is my array.
const categories = [
"Department of Natural Science",
"Department of public health and sanitation",
"Department of culture and heritage of state"
];
Again by splitting each string I want to change it to an array. This array contains several chunk of the string. For eg. by splitting Department of culture and heritage of state string I want this to separate Department of Natural Science. Here I want to create every different chunk if the chunk contains more than 13 character in length. That's why Natural and Science separated because if we sum of the length of them it becomes 14 .
Here is what I have tried.
const categories = [
"Department of Natural Science",
"Department of public health and sanitation",
"Department of culture and heritage of state"
];
const arrayOfAllString = []; // results at the end
categories.map(cur => {
// looping the array
const splitedItems = cur.trim().split(" "); // splitting the current string into words
const arrayOfSingleString = []; //
let str = "";
splitedItems.map(item => {
// looping the array of splitted words
if (str.length + item.length > 13) {
// trying to make a chunk
arrayOfSingleString.push(str);
str = ""; // clearing the str because it has been pushed to arrayOfSingleString
} else {
str = str.concat(item + " "); // concat the str with curent word
}
});
arrayOfAllString.push(arrayOfSingleString);
});
console.log(arrayOfAllString);
My expected result would be somehow look like this :
arrayOfAllString = [
["Department of", "Natural", "Science"],
["Department of", "public health", "and", "sanitation"],
["Department of", "culture and", "heritage of", "state"]
];
You could take a generator and return chunks in the wanted length.
function* getJoined(string, size) {
var array = string.split(' '),
i = 0;
while (i < array.length) {
let s = array[i];
while (++i < array.length && (s + array[i]).length < size) {
s += ' ' + array[i];
}
yield s;
}
}
console.log([...getJoined('Department of culture and heritage of state', 13)]);
Classic approach without missusing map.
function getJoined(string) {
var array = string.split(' '),
size = 13,
i = 0,
result = [];
while (i < array.length) {
let s = array[i];
while (++i < array.length && (s + array[i]).length < size) {
s += ' ' + array[i];
}
result.push(s);
}
return result;
}
const categories = ["Department of Natural Science", "Department of public health and sanitation", "Department of culture and heritage of state"];
console.log(categories.map(getJoined));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Made few changes.
1) while clearing, change to str = item; instead of str = ''
2) End of loop, do arrayOfSingleString.push(str); for adding last item.
const categories = [
"Department of Natural Science",
"Department of public health and sanitation",
"Department of culture and heritage of state"
];
const arrayOfAllString = categories.map(cur => {
const splitedItems = cur.trim().split(" ");
const arrayOfSingleString = [];
let str = "";
while (splitedItems.length > 0) {
const item = splitedItems.shift();
if (str.length + item.length >= 13) {
// trying to make a chunk
arrayOfSingleString.push(str);
// clearing the str because it has been pushed to arrayOfSingleString
str = item;
} else {
// concat the str with curent word
str = str ? `${str} ${item}` : item;
}
}
arrayOfSingleString.push(str);
return arrayOfSingleString;
});
console.log(arrayOfAllString);

How to find all combination of an array in javascript

I'm using node.js currently, and i would like to find / try all the unique possibilities resulting from the combinations of data stored in an array.
Example :
// source array
var array = [0,1,2];
// what i need :
0
1
2
00
01
02
10
11
12
20
21
22
000
001
002
etc, up to a configurable length.
I've looked on the forums and didn't manage to find something like this.
I've searched on npm and found some librairies that are doing similar things, but never all the possibilities i need. I'm feeling like my need is very similar to a bubble sorting algorithm, but i don't know how to do this.
Also it would be very much better to do it without storing the whole output in a variable at the same time, as the idea is that my code needs to work with larger arrays.
Any idea or solution i missed would help at this point !
Edit : Also, i would like to continuously try combination until i decide it's enough, such as 500 try or if the last combination length is 5 for example.
Another approach, with several reusable functions:
const flatten = arrays => [].concat.apply([], arrays);
const range = (lo, hi) => [...new Array(hi - lo + 1)].map((_, i) => i + lo)
const join = joiner => list => list.join(joiner)
const charSeqs = (n, chars) => (n < 1)
? [[]]
: flatten(chars.map(char => charSeqs(n - 1, chars).map(
seq => flatten([char].concat(seq))
)))
const allCharSeqs = (n, chars) => flatten(range(1, n).map(i => charSeqs(i, chars)))
console.log(allCharSeqs(3, [0, 1, 2]).map(join('')))
function variations(arr, length) {
if (length == 0)
return [];
else if (length == 1)
return arr.map(e => e.toString());
let result = [];
for (let i = 0; i < arr.length; i++) {
for (let tail of variations(arr, length - 1))
result.push(arr[i].toString() + tail);
}
return result;
}
function variations2(arr, maxLength) {
let result = [];
for (let i = 0; i <= maxLength; i++)
result = result.concat(variations(arr, i));
return result;
}
Example:
var array = [0,1,2];
console.log(variations2(array, 2));
Output:
["0", "1", "2", "00", "01", "02", "10", "11", "12", "20", "21", "22"]

Split array of string with multiple delimiters and store in separate arrays

I have a Javascript object like
Object = { "ratio1" : "12+45*36",
"ratio2" : "34+45*16",
"ratio3" : "17+25"}
I am trying to split the values like the values before + in one array and values after + in one array . so the output should be like
Array1= ["12" , "34" , "17"]
Array2 = ["45" , "36" , "45","16","25"].
To perform this I am iterating through the keys and getting the values first then I am again iterating through the values array I am splitting it using
ratioArray.split("+");
This gave me [[" 12" , "45*36"], [" 34", "45*16"], [" 17", "25"]]
Now again I have iterate through all the three arrays and split using second delimiter. Is there any efficient way to perform this so that I can reduce these many iterations
const ratios = {
"ratio1" : "12+45*36",
"ratio2" : "34+45*16",
"ratio3" : "17+25"
}
const nums = Object.keys(ratios)
.map(key => ratios[key]
.replace(/[+*]/g, '|')
.split('|')
)
const [ array1, array2, array3 ] = nums
document.querySelector('pre').innerText =
`array1 === [${array1}]\n` +
`array2 === [${array2}]\n` +
`array2 === [${array3}]\n`
<pre />
var Object = {
"ratio1": "12+45*36",
"ratio2": "34+45*16",
"ratio3": "17+25"
}
var Array1 = [],
Array2 = [],
temp;
for (var key in Object) {
temp = Object[key].split('+');
Array1.push(temp[0])
temp = temp[1].split('*')
for(var i = 0; i < temp.length; i++){
Array2.push(temp[i])
}
}
console.log('Array1:['+Array1[0]+','+Array1[1]+','+Array1[2]+']')
console.log('Array2:['+Array2[0]+','+Array2[1]+','+Array2[2]+','+Array2[3]+','+Array2[4]+']')
You can do something like this.
object = {
"ratio1": "12+45*36",
"ratio2": "34+45*16",
"ratio3": "17+25"
}
var array1 = [],
array2 = [];
for (var key in object) {
var _o = object[key].split("+");
array1.push(_o[0]);
_o[1].split("*").forEach(function(num) {
array2.push(num);
})
};
console.log("array 1", array1);
console.log("array 2", array2)

Getting average of every item of multiple arrays into one array

Well my brains are melting... I am trying to accomplish the following:
I know how many arrays and how many elements each array have.
These numbers are dynamic, but lets say there's: 3 arrays with 18 elements in each.
Example:
["106","142","112","77","115","127","87","127","156","118","91","93","107","151","110","79","40","186"]
["117","139","127","108","172","113","79","128","121","104","105","117","139","109","137","109","82","137"]
["111","85","110","112","108","109","107","89","104","108","123","93","125","174","129","113","162","159"]
Now I want to get the average of element 1 of all three arrays, and element 2 of all three and so on.
The end result should be one array with the average of all 18 elements.
Something like:
var result_array = [];
for (i = 0; i < 3; i++) {
result_array.push(arrayone[i] + arraytwo[i] + arraythree[i]) / 3
}
This would work if 3 was fixed, but the amount of arrays is dynamic.
Hope this make sense...
var arrays = [
[106,142,112,77,115,127,87,127,156,118,91,93,107,151,110,79,40,186],
[117,139,127,108,172,113,79,128,121,104,105,117,139,109,137,109,82,137],
[111,85,110,112,108,109,107,89,104,108,123,93,125,174,129,113,162,159],
[104,153,110,112,108,109,107,89,104,108,123,93,125,174,129,113,162,159]
/* Can be any amount of arrays */
],
result = [];
//Rounding to nearest whole number.
for(var i = 0; i < arrays[0].length; i++){
var num = 0;
//still assuming all arrays have the same amount of numbers
for(var i2 = 0; i2 < arrays.length; i2++){
num += arrays[i2][i];
}
result.push(Math.round(num / arrays.length));
}
alert(result);
You did tag this question with underscore.js, so you can use the _.zip method. This puts all the first elements in an array together and so on. You can then average each of those arrays.
See CodePen.
var arr1 = ["106","142","112","77","115","127","87","127","156","118","91","93","107","151","110","79","40","186"]
var arr2 = ["117","139","127","108","172","113","79","128","121","104","105","117","139","109","137","109","82","137"]
var arr3 = ["111","85","110","112","108","109","107","89","104","108","123","93","125","174","129","113","162","159"]
// ... as many more arrays as you want
var avgEmAll = function (arrays) {
// zip with array of arrays https://stackoverflow.com/a/10394791/327074
return _.zip.apply(null, arrays).map(avg)
}
// average an array https://stackoverflow.com/a/10624256/327074
var avg = function (x) {
return x.reduce(function (y, z) {return Number(y) + Number(z)}) / x.length
}
console.log(avgEmAll([arr1, arr2, arr3]))
With ES6 arrow functions (CodePen):
const avgEmAll = arrays => _.zip.apply(null, arrays).map(avg)
const sum = (y, z) => Number(y) + Number(z)
const avg = x => x.reduce(sum) / x.length
Wrote this solution in Java but you can get help with logic. Hope it helps.
ArrayList<Integer> averageArrayList = new ArrayList<>();
int arrayListLength = arrayList1.length(); //assuming previous arraylists have same size.
for(int i=0; i<arrayListLength; i++){
int averageValue = (arrayList1.get(i) + arrayList2.get(i) + arrayList3.get(i)) / 3;
//adds average value to current index.
averageArrayList.add(i, averageValue);
}
//averageArrayList is ready with your values..
var result = getAvg( [ 1, 2, 3 ], [ 2, 3, 4 ] )
console.log( result ) // [ 1.5, 2.5, 3.5 ]
function getAvg() {
var a = arguments
var nar = a.length
var nel = a[ 0 ].length
var el, ar, avg, avgs = []
for( el = 0; el < nel; ++el ) {
avg = 0
for( ar = 0; ar < nar; ++ar ) avg += a[ ar ][ el ]
avgs[ el ] = avg / nar
}
return avgs
}
This function will take any number of arrays and figure out their average. It uses the + operator to automatically cast the string to a number. It is dynamic in that it doesn't care what length the arrays are, or how many there are, as long as they are all equal in length. Since we can assume that they are all the same length( based on the question ) it iterates over the length of the first array. It doesn't round because that wasn't asked for.
function average_of_arrays(...arrays) {
let result = [];
for(let array_index in arrays[0]) {
let total = 0;
for (let arr of arrays) {
total += +arr[array_index]
}
result.push(total / arrays.length);
}
return result;
}
let arr1 = ["106", "142", "112", "77", "115", "127", "87", "127", "156", "118", "91", "93", "107", "151", "110", "79", "40", "186"];
let arr2 = ["117", "139", "127", "108", "172", "113", "79", "128", "121", "104", "105", "117", "139", "109", "137", "109", "82", "137"];
let arr3 = ["111", "85", "110", "112", "108", "109", "107", "89", "104", "108", "123", "93", "125", "174", "129", "113", "162", "159"];
function average_of_arrays(...arrays) {
let result = [];
for(let array_index in arrays[0]) {
let total = 0;
for (let arr of arrays) {
total += +arr[array_index]
}
result.push(total / arrays.length);
}
return result;
}
console.log(average_of_arrays(arr1, arr2, arr3));
The answer here is to use a loop. Let's call your arrays arr1, arr2, and arr3.
var averages = [];
for(i = 0; i < arr1.length; i++) {
var a = arr1[i];
var b = arr2[i];
var c = arr3[i];
var avg = (a + b + c) / 3;
averages.push(avg);
}
For each iteration of this loop, it will:
-Assign the next digit of each array to a variable (starting at index 0)
-Find the average of the three numbers
-Add the result of the calculation to the averages array

Categories

Resources