Javascript - Adding multiple values to keys - javascript

I am trying to find the places of each letter in a sentence by using "dictionaries". The problem is I want to find all the places that each letter is and not only the last one. I am very new to JavaScript and couldn't figure out the way to do it.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g,'');
var dict = {};
for (var i=0; i < stringArgument.length; i++ )
if (!stringArgument[i] in dict){
dict[stringArgument[i]] = [];
}else{
dict[stringArgument[i]] = [i+1]
}
return dict
}
var a = letters('Lost time is never found again.');
console.log(a);
naturally gives this output:
{ L: [ 1 ], o: [ 17 ], s: [ 10 ], t: [ 5 ]...
but it should give this:
{ L: [ 1 ], o: [ 2, 17 ], s: [ 3, 10 ], t: [ 4, 5 ]...
Also each letter is saved to the dictionary at the same order they appear in the sentence, how can I order the letters alphabetically?

What you need is a function that gets the positions of a character in a given string.
Try this:
function findAllPositions(char, content) {
var result = [];
let index = content.indexOf(char);
while(index !== -1) {
result.push(index);
index = content.indexOf(char, index + 1);
}
return result;
}
findAllPositions('o', 'Lost time is never found again.'); // Result =  [1, 20]
Using this we can update the letter function as follows:
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, '');
var dict = {};
for (const char of stringArgument) {
dict[char] = findAllPositions(char, stringArgument)
}
return dict;
}
letters('is again.')
/*
{
"i": [0, 5],
"s": [1],
"a": [2, 4],
"g": [3],
"n": [6],
".": [7]
}
*/

You need to have
parantheses for the check
if (!(stringArgument[i] in dict)) {
create an array if the above is true
push the postion to the array
For getting a sorted output, you could take the entries of the object, apply a sorting by taking the key and show the result in order.
Object have an insertation oder for not positive 32 bit numbers (like indixes) or symbols. The index like numbers are sorted by value and appears first in the object.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, '');
var dict = {};
for (var i = 0; i < stringArgument.length; i++) {
if (!(stringArgument[i] in dict)) {
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i + 1);
}
return dict;
}
var a = letters('Lost time is never found again.');
Object
.entries(a)
.sort(([a], [b]) => a.localeCompare(b))
.forEach(([key, positions]) => console.log(key, ...positions));
console.log(a);

First, for any item, if it is not in an empty array:
var notInDict = !(stringArgument[i] in dict);
If not in dict, then initialize an empty array and push the item in it using
dict[stringArgument[i]].push(i + 1);
Try this.
function letters(stringArgument) {
stringArgument = stringArgument.replace(/ /g, "");
var dict = {};
for (var i = 0; i < stringArgument.length; i++) {
var notInDict = !(stringArgument[i] in dict);
if (notInDict) {
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i + 1);
}
return dict;
}
var a = letters("Lost time is never found again.");
console.log(a);

you are assigning a new array at each iteration
dict[stringArgument[i]] = [i+1]
what you need to do is push the new position to existing array.
dict[stringArgument[i]].push(i+1)
also, remove the else block
function letters(stringArgument) {
stringArgument = stringArgument.toLowerCase().replace(/ /g,'');
var dict = {};
for (var i=0; i < stringArgument.length; i++ ){
if (!dict.hasOwnProperty(stringArgument[i])){
dict[stringArgument[i]] = [];
}
dict[stringArgument[i]].push(i+1);
}
//sorting
var letters = Object.keys(dict); //returns a array
letters.sort();
var sortedDic = {};
for(var i in letters) {
sortedDic[letters[i]] = dict[letters[i]];
}
return sortedDic;
}
var a = letters('Lost time is never found again.');
console.log(a);

for the first part you can also do that:
let sentence = 'Lost time is never found again.'
let tabLetters = [...sentence.replace(/ /g,'')].reduce((a,c,i)=>
{
if (!a[c]) a[c] = [i+1]
else a[c].push(i+1)
return a
},{})
document.write(JSON.stringify(tabLetters))

Related

How to sort an array according to another array in javascript?

I count the words in a paragraph by frequency of occurrences now I need to sort them too for example [this : 2, is : 3, it : 1] to [is : 3, this : 2, it : 1]. I divided keys and values into two different arrays then I sorted an array of values now I want to sort an array of keys
console.log('app running');
function getFrequencyOfWord(word : string) {
let counting: any = {};
let wordSplit: any = word.split(' ');
wordSplit.forEach(function (word: any) {
if (counting[word]) {
counting[word]++;
}
else {
counting[word] = 1;
}
})
var arr1 = Object.keys(counting);
var arr2 = arr1.map((suboor)=> {
return counting[suboor];
});
for (var i : number = 0; i < arr2.length; i++) {
for (var j = 0; j < (arr2.length -i -1); j++) {
if (arr2[j] > arr2[j+1]) {
const lesser = arr2[j+1];
arr2[j+1] = arr2[j];
arr2[j] = lesser;
}
}
}
console.log(arr2);
console.log(arr1);
}```
You could try something like the following:
let word = "moo moo moo hello one two three one";
let wordSplit = word.split(' ');
var counting = [];
wordSplit.forEach(function (word) {
if (counting[word]) {
counting[word]++;
}
else {
counting[word] = 1;
}
})
console.log("Counting ...");console.log(counting);
function swap(json){
var ret = {};
for(var key in json){
let element = ret[json[key]] ;
//console.log("element");console.log(element);
if(element == undefined){
ret[json[key]] = element= [];
}
element.push(key);
//console.log("element");console.log(element);
}
return ret;
}
let result = swap(counting);
console.log("RESULT ...");console.log(result);
var finalResult = [];
for(var key in result){
finalResult = finalResult.concat(result[key]);
}
console.log("Final RESULT ...");console.log(finalResult);
Output
Word Count:
[moo: 3, hello: 1, one: 2, two: 1, three: 1]
Result:
{1: Array(3), 2: Array(1), 3: Array(1)}
1: (3) ["hello", "two", "three"]
2: ["one"]
3: ["moo"]
Final Result
0: "hello"
1: "two"
2: "three"
3: "one"
4: "moo"
Fiddle: https://jsfiddle.net/menelaosbgr/xe9u7mqk/33/
Update
The problem is that you actually have a map of object instead of an array. An array of objects would be something like [{is:3},{this:2},{it:1}] . It's not that difficult to do the conversion. However, I think it's better to have objects that are like this {word:X, count:x}. See below:
let word = "this this is is it is";
let wordSplit = word.split(' ');
var counting = [];
wordSplit.forEach(function (word) {
if (counting[word]) {
counting[word]++;
}
else {
counting[word] = 1;
}
})
console.log("Counting ...");console.log(counting);
function swap(json){
var ret = {};
for(var key in json){
let element = ret[json[key]] ;
//console.log("element");console.log(element);
if(element == undefined){
ret[json[key]] = element= [];
}
element.push({count:json[key], word:key});
//console.log("element");console.log(element);
}
return ret;
}
let result = swap(counting);
console.log("RESULT ...");console.log(result);
//Reverse it and make it into objects...
let reversedResult = Object.assign([], result ).reverse();
console.log("RESULT-REVERSED ...");console.log(reversedResult);
//Final Conatenated Array
var concatenatedArray = [];
for(var key in reversedResult){
concatenatedArray = concatenatedArray.concat(reversedResult[key]);
}
console.log("CONCATENATED-ARRAY ...");console.log(concatenatedArray);
Result:
0: {count: 3, word: "is"}
1: {count: 2, word: "this"}
2: {count: 1, word: "it"}
Fiddle: https://jsfiddle.net/menelaosbgr/xe9u7mqk/49/
This is not possible to sort array of keys according to array of values but you can do something to map right key to right value by checking if(arr[key] == arr[value]) and if key and value are equal then you can push that key value pair into new array.

Matching 3 or more same elements in a array and adding them to a list

I am trying to find 3 or more matching items in array but it is only matching the first 3 and none matching for the rest of the array. If anyone could help would be great :)
var grid = [2,2,2,5,5,5,3,3,3,3];
checkResults();
function checkResults(){
var list_matches = []; // store all matches found
var listcurrent = []; // store current
var maxitems = 3;
var last = -1; // last cell
for(let j =0; j < grid.length; ++j){
let item = grid[j];
// check if last is null
if(last == -1){
// add first item
listcurrent.push(item);
last = item;
console.log("Added: "+item);
continue;
}
let wasMatch = false;
// check match
if(item == last){
wasMatch = true;
listcurrent.push(item);
last = item;
console.log("Added Match: "+item);
}
if(!wasMatch){
console.log("Not matched: " + item);
if(listcurrent.length >= maxitems){
list_matches.push(listcurrent);
}
// reset to null
last = -1;
listcurrent = [];
}
}
console.log(list_matches);
console.log("Cols: " + grid.length);
}
Expected Results: from [2,2,2,5,5,5,3,3,3,3];
0: 222
1: 555
2: 3333
Current output is:
0: 222 and thats it
You could take a temporary array for collecting the same values and push this array if the length has the wanted minimum length.
function getMore(array, min) {
var result = [],
temp;
array.forEach((v, i, a) => {
if (v !== a[i - 1]) return temp = [v];
temp.push(v);
if (temp.length === min) result.push(temp);
});
return result;
}
console.log(getMore([2, 2, 2, 5, 5, 5, 3, 3, 3, 3], 3));
you can do something like this:
var grid = [ 1, 1, 2, 3, 4, 5 ];
var hashMap = {};
for( var i = 0; i < grid.length; i++ ) {
if( hashMap.hasOwnProperty( grid[i] ) ) {
hashMap[ grid[i] ]++;
} else {
hashMap[ grid[i] ] = 1;
}
}
it will helps you.
//toLowerCase for get unique on words, not on character. if i ignore this, it will return two words=> developers. and developers
//first Split and join for remove '.' character form text and finally last split is for convert string to an Array of words that splited by Space character
let uniqWords = Array.from(new Set(text));
//using Set to get unique words and convert it to Array to do more on Array.
let count = {};
// declare varriable for store counts of words.
uniqWords.map(item => {
count[item] = text.filter(elem => {
//create property with the name of words and filter common words to an Array
return elem == item
}).length
//get Array length for get words repeated count.
})
console.table(count)
//log Result into Console
Another solution using Array.prototype[reduce/map/filter]
const someArray = [2, 2, 2, 5, 5, 5, 3, 3, 3, 3, 9, 9];
console.log(aggregate(someArray));
function aggregate(arr) {
return arr
// retrieve unique values
.reduce((acc, val) => !acc.includes(val) && acc.concat(val) || acc, [])
// use unique values to map arr values to strings
// if number of matches >= 3
.map(val => {
const filtered = arr.filter(v => v == val);
return filtered.length > 2 ? filtered.join("") : false
})
// filter non falsy values
.filter(val => val);
}

Find the Words with an even number of occurrences in an Array - Javascript

Given an array of words, write a function that returns an array of the words that occur an even number of times.
function even(["hello", "hi", "hello", "elephant", "hi"]);
That output should be:
["hello", "hi"]
This has been a toy problem I have been struggling with recently. I have solved similar problems counting and returning the number of occurrences of elements in an array but am having trouble taking that logic and applying it to this problem.
This is what I have tried so far, but have hit a wall when trying to output just the even occurrences:
function even(collection) {
var results = [];
for(var i = 0; i < collection.length; i++){
var value = collection[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
return results;
}
You can use reduce to get an actual count of the words, then simply return an array of the ones that have an even count:
function even(wordsArr) {
//Object of words and counts
var wordCounts = wordsArr.reduce(function(counts, word) {
if (!counts.hasOwnProperty(word)) {
counts[word] = 0;
}
counts[word]++;
return counts;
}, {});
//Now filter that out and return
return Object.keys(wordCounts).filter(function(word) {
return wordCounts[word] % 2 === 0
});
}
even(["hello", "hi", "hello", "elephant", "hi"]); //["hello", "hi"]
var arr = ["hello", "hi", "hello", "elephant", "hi"];
function onlyEvens( arr )
{
var countObj = {};
for( var i = 0; i < arr.length; i++ )
{
var item = arr[i];
if( countObj[ item ] !== undefined )
countObj[item]++;
else
countObj[item] = 1;
}//for()
var filteredArray = [];
for(var key in countObj )
{
if( countObj[key] % 2 == 0 )
filteredArray.push( key );
}
return filteredArray;
}//onlyEvens()
console.log( onlyEvens( arr ) );
Issues in your code:
you use collection instead of words
you cannot access array the associative way. You must declare it as object:
results[value]
you return result variable, but it is undeclared.
return result;
results only contains the occurrences of every word. There miss the code that calculates if the occurrences of a word are odd or even.
fixed code:
function even(words) { // <<< in your code was collection
var results = {};
for(var i = 0; i < words.length; i++){
var value = words[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
var ret = [];
for(var word in results)
if(results[word]%2 !== 0)
rest.push(word);
return ret;
}
function even(list) {
var d = list.reduce(function(d, w) { d[w] = !d[w]; return d; }, {});
return Object.keys(d).filter(function(w) { return !d[w]; });
}
console.log(even(["hello", "hi", "hello", "elephant", "hi"]));
console.log(even(["hello", "yo", "yo", "hi", "hello", "yo", "elephant", "hi"]));
Explanation: Use the array .reduce() method to create an object (d) with a property for each word (w) with a boolean value indicating whether the word has an odd number of occurrences. Then .filter() the keys to get all the ones that are not odd.
If you previously sort the array you can filter it as required in just a code line like this :
var even = (str) => str.sort().filter((element, index, arr) => index+1 === arr.lastIndexOf(element));
console.log(even(["hello", "hello", "hi", "elephant", "hi", "hi"])); //[ 'hello', 'hi' ]

Store count of integers in order using javascript

I have string like the following:
11222233344444445666
What I would like to do is output the number followed the times it was displayed:
112433475163
Question is, I want this to be efficient. I can store this in an object as the following:
1: { id: 1, displayed: 2},
2: { id: 2, displayed: 1},
3: { id: 3, displayed: 2},
etc.
I can access this object and increment displayed.
My issues is, there is no guarantee in the order. I would like to store the keys in the order they are in the string. How do I accomplish the importance of the order in the object?
This is a proposal for run length coding with an array which holds infomation about one charcter and the count of it:
{
"char": "1",
"count": 2
},
var string = "11222233344444445666",
array = function () {
var r = [], o = {};
string.split('').forEach(function (a, i, aa) {
if (a !== aa[i - 1]) {
o[a] = { char: a, count: 0 };
r.push(o[a]);
}
o[a].count++;
});
return r;
}(string);
document.write('<pre>' + JSON.stringify(array, 0, 4) + '</pre>');
Quick solution with for loop:
var str = "7771122229933344444445666",
obj = {},
len = str.length,
val = null,
count_str = "",
key = "";
for (var i = 0; i < len; i++) {
val = str[i], key = 'k' + val;
if (!obj[key]) {
obj[key] = {'id': val, 'displayed': 1};
} else {
obj[key].displayed++;
}
}
for (var p in obj) {
count_str += obj[p]['id'] + obj[p]['displayed'];
}
console.log(count_str); // "7312249233475163"
because you have such a small set of distinct numbers, I seen no reason why you can't use a array (yeah it's not super ideal memorywise if you skip values and it becomes sparse, but for such a small subset it won't affect you enough to worry of it). Then you can use (number-1) as the index and increment that number as needed.
var counts = [];
var str = "11222233344444445666";
for(var i in str){
var index = parseInt(str[i])-1
counts[index] = (counts[index]||0)+1;
}
for(var i in counts){
var which = 1+parseInt(i);
var count = counts[i];
console.log("# of " + which +"'s: "+count);
}
https://jsfiddle.net/ga0fqpqn/
note: You shouldn't need the parseInt(i)... just +i should work but I think jsfiddle has a bug with it about it defaulting i to handle like a string.
You could store an additional array with the order of the numbers, which you only append to if the object doesn't yet contain the given number. Then once you're done counting, iterate through that array and output the number and the count from the lookup dictionary.
var chars = "1234576123452345".split("");
var order = [];
var hash = {};
chars.forEach(function(char) {
if (!hash[char]) {
hash[char] = 1;
order.push(char);
} else {
hash[char]++;
}
});
console.log(order.map(function(char) {
return char + hash[char];
}).join(""));
// "12233343537161"

Javascript merge 2 arrays and sum same key values

I have 2 array:
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
Want to get 1 merged array with the sum of corresponding keys;
var array1 = [[1,10],[2,10],[3,10],[4,10],[5,50],[6,50],[7,10],[8,10],[9,10]];
Both arrays have unique keys, but the corresponding keys needs to be summed.
I tried loops, concat, etc but can't get the result i need.
anybody done this before?
You can use .reduce() to pass along an object that tracks the found sets, and does the addition.
DEMO: http://jsfiddle.net/aUXLV/
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
var result =
array1.concat(array2)
.reduce(function(ob, ar) {
if (!(ar[0] in ob.nums)) {
ob.nums[ar[0]] = ar
ob.result.push(ar)
} else
ob.nums[ar[0]][1] += ar[1]
return ob
}, {nums:{}, result:[]}).result
If you need the result to be sorted, then add this to the end:
.sort(function(a,b) {
return a[0] - b[0];
})
This is one way to do it:
var sums = {}; // will keep a map of number => sum
// for each input array (insert as many as you like)
[array1, array2].forEach(function(array) {
//for each pair in that array
array.forEach(function(pair) {
// increase the appropriate sum
sums[pair[0]] = pair[1] + (sums[pair[0]] || 0);
});
});
// now transform the object sums back into an array of pairs
var results = [];
for(var key in sums) {
results.push([key, sums[key]]);
}
See it in action.
a short routine can be coded using [].map()
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
array1=array2.concat(array1).map(function(a){
var v=this[a[0]]=this[a[0]]||[a[0]];
v[1]=(v[1]||0)+a[1];
return this;
},[])[0].slice(1);
alert(JSON.stringify(array1));
//shows: [[1,10],[2,10],[3,10],[4,10],[5,50],[6,50],[7,10],[8,10],[9,10]]
i like how it's just 3 line of code, doesn't need any internal function calls like push() or sort() or even an if() statement.
Try this:
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
var res = [];
someReasonableName(array1, res);
someReasonableName(array2, res);
function someReasonableName(arr, res) {
var arrLen = arr.length
, i = 0
;
for(i; i < arrLen; i++) {
var ar = arr[i]
, index = ar[0]
, value = ar[1]
;
if(!res[index]) {
res[index] = [index, 0];
}
res[index][1] += value;
}
}
console.log(JSON.stringify(res, null, 2));
So, the result may have holes. Just like 0th index. Use the below function if you want to ensure there are no holes.
function compact(arr) {
var i = 0
, arrLen = arr.length
, res = []
;
for(i; i < arrLen; i++) {
var v = arr[i]
;
if(v) {
res[res.length] = v;
}
}
return res;
}
So, you can do:
var holesRemoved = compact(res);
And finally if you don't want the 0th elem of res. Do res.shift();
Disclaimer: I am not good with giving reasonable names.
The simple solution is like this.
function sumArrays(...arrays) {
const n = arrays.reduce((max, xs) => Math.max(max, xs.length), 0);
const result = Array.from({ length: n });
return result.map((_, i) => arrays.map(xs => xs[i] || 0).reduce((sum, x) => sum + x, 0));
}
console.log(...sumArrays([0, 1, 2], [1, 2, 3, 4], [1, 2])); // 2 5 5 4

Categories