Counting letters and numbers in string - javascript

I write a code that works with letter but not with numbers
I know it maybe a little complicated but this is how I could do it;
with numbers it produce ordered Array and I don't know why
var orderedCount = function(text) {
let splitted = text.split('');
let countedLetters = splitted.reduce((AllLetters, letter) => {
(letter in AllLetters) ? AllLetters[letter]++: AllLetters[letter] = 1;
return AllLetters
}, {})
let result = Object.keys(countedLetters).map((key) => {
return [(key), countedLetters[key]]
})
return result;
};
console.log(orderedCount("abracadabra")); //[['a',5], ['b',2], ['r',2], ['c',1], ['d',1]]
console.log(orderedCount("212")); //[['1',1], ['2',2]]
[['1',1],['2',2]]
should be
[['2',2],['1',1]]

You can use Object.entries to convert the object into an array and use sort to sort the element 1
var orderedCount = function(text) {
let splitted = text.split('');
let countedLetters = splitted.reduce((AllLetters, letter) => {
(letter in AllLetters) ? AllLetters[letter]++: AllLetters[letter] = 1;
return AllLetters
}, {})
let result = Object.entries(countedLetters).sort((a, b) => {
return b[1] - a[1];
})
return result
};
console.log(orderedCount("abracadabra"));
console.log(orderedCount("212"));
Shorter Version:
var orderedCount = function(text) {
return Object.entries(text.split('').reduce((c, v) => {
c[v] = (c[v] || 0) + 1;
return c;
}, {})).sort((a, b) => b[1] - a[1]);
};
console.log(orderedCount("abracadabra"));
console.log(orderedCount("212"));

You can create the array directly using Array#reduce method where use a reference object which keeps object reference based on letter value.
var orderedCount = function(text) {
const ref = {};
return text.split('').reduce((arr, letter) => {
(letter in ref) ? ref[letter][1]++: arr.push(ref[letter] = [letter, 1]);
return arr;
}, []);
};
console.log(orderedCount("abracadabra")); //[['a',5], ['b',2], ['r',2], ['c',1], ['d',1]]
console.log(orderedCount("212")); //[['1',1], ['2',2]]
Refer : Does JavaScript Guarantee Object Property Order?
Since es2015 onwards non-integer keys are kept inserting order and integer keys are sorted numerically.

You need to sort you result by count, because by default numeric keys in Object will be in ascending order
var orderedCount = function(text) {
let splitted = text.split('');
let countedLetters = splitted.reduce((AllLetters, letter) => {
(letter in AllLetters) ? AllLetters[letter]++: AllLetters[letter] = 1;
return AllLetters
}, {})
let result = Object.keys(countedLetters).map((key) => {
return [(key), countedLetters[key]]
})
return result.sort((a,b)=>b[1] - a[1]);
};
console.log(orderedCount("abracadabra")); //[['a',5], ['b',2], ['r',2], ['c',1], ['d',1]]
console.log(orderedCount("212")); //[['1',1], ['2',2]]

Related

Return all possible combinations of array with optional strings

Lets say I have an array keys = ["the?", "orange", "van", "s?"], with '?' at the end of strings to represent that it is optional.
I want a function in javascript generateCombinations(keys) that returns the possible combinations such as :
[["orange","van"],["the","orange","van"],["orange","van","s"],["the","orange","van","s"]]
One possible way of removing '?' is to simply do a replace("?',"").
I have a feeling it might require a recursive function, which I am not yet quite strong in. Help is appreciated!
So far I've tried this:
function isOptionalKey(key) {
return key.endsWith('?');
}
function hasOptionalKey(keys) {
return keys.some(isOptionalKey);
}
function stripOptionalSyntax(key) {
return key.endsWith('?') ? key.slice(0, -1) : key;
}
function generateCombinations(keys) {
if (keys.length === 1) {
return keys;
}
const combinations = [];
const startKey = keys[0];
const restKeys = keys.slice(1);
if (hasOptionalKey(restKeys)) {
const restCombinations = isOptionalKey(startKey)
? generateCombinations(restKeys)
: restKeys;
if (isOptionalKey(startKey)) {
combinations.push(restCombinations);
}
combinations.push(
restCombinations.map((c) => [stripOptionalSyntax(startKey), ...c])
);
} else {
if (isOptionalKey(startKey)) {
combinations.push(restKeys);
}
combinations.push([stripOptionalSyntax(startKey), ...restKeys]);
}
return combinations;
}
You could take a recursive approach by using only the first item of the array and stop if the array is empty.
const
getCombinations = array => {
if (!array.length) return [[]];
const
sub = getCombinations(array.slice(1)),
optional = array[0].endsWith('?'),
raw = optional ? array[0].slice(0, -1) : array[0],
temp = sub.map(a => [raw, ...a]);
return optional
? [...temp, ...sub]
: temp;
};
keys = ["the?", "orange", "van", "s?"],
result = getCombinations(keys);
console.log(result.map(a => a.join(' ')));

Looping data from json using Array

I'm trying to write a function but I doesn't make it. This function works like that
Input: changeSetting("a>b>c","hello")
After that "setting" named value change from {} to {"a":{"b":{"c":"hello"}}}
If input is changeSetting("a","hello") json become {} to {"a":"hello"}
My last code attempt:
function changeSetting(name,val) {
if (name.includes(">")) {
name = name.split('>')
let json = {}
name.map((el,i)=>{
let last = ""
name.filter(el=>!name.slice(i+1).includes(el)).map(el=> {
if(last!="") {
json[el] = {}
}})
})
}
}
How can we make this ? (Optimization not important but if is it good for me)
const changeSetting = (setting, target) => {
if (setting.length < 2) {
return {
[setting]: target
}
} else {
const keys = setting.split('>');
return keys.reduceRight((acc, curr, i) => {
console.log(acc);
if(i === keys.length - 1) {
return acc = {[curr] : target}
}
return acc = { [curr]: acc };
}, {})
}
}
console.log(changeSetting('a', 'hello'));
console.log(changeSetting('a>b>c', 'hello'));
function changeSetting(inputProperties, value) {
let result;
const properties = inputProperties.split(">");
result = `{${properties
.map((property) => `"${property}":`)
.join("{")}"${value}"${"}".repeat(properties.length)}`;
return result;
}
changeSetting("a>b>c", "hello");
changeSetting("a", "hello");
As you work with strings - you may try to use JSON like this:
function changeSetting(name, val) {
const keys = name.split(">");
return JSON.parse(
[
"{",
keys.map((key) => `"${key}"`).join(":{"),
":",
`"${val}"`,
"}".repeat(keys.length),
].join("")
);
}
There's multiple ways to do this, I've commented the snippet
const changeSetting = (name, val) => {
// Split and reverse the name letters
const nameSplit = name.split('>').reverse();
// Set up the inner most object
let newObj = {[nameSplit[0]]:val}
// Now remove the first letter and recurse through the rest
nameSplit.slice(1).forEach((el, idx) => newObj = {[el]: newObj});
console.log(newObj);
}
changeSetting("a>b>c", "hello")
changeSetting("a", "hello")
changeSetting("a>b>c>d>e>f>g", "hello")
You can create an array by splitting name on all > with String.prototype.split(), and then Array.prototype.reduceRight() the created array of elements with an object initial value {} and adding key value pairs but on the last element the value should be variable val.
Code:
const changeSetting = (name, val) => name
.split('>')
.reduceRight((a, c, i, arr) => ({
[c]: i === arr.length - 1 ? val : a
}), {})
console.log(changeSetting('a>b>c', 'hello'))
console.log(changeSetting('a', 'hello'))
console.log(changeSetting('a>b>c>d>e>f>g', 'hello'))

How could I find intersections in a string array with a variable number of elements?

I have a function that receives an array composed of numerical, comma separated strings as input, then finds the intersectional numbers in those strings and returns a string of similarly comma separated numbers, with no spaces, containing those intersections. If there are no intersections between the two elements, the function will return false.
What I want is to optimize the function so that it can work with a string array that may have more than just two elements. Is that possible? If so, could I have some sort of guideline of where to start looking for answers?
Currently, this is what I have.
function LocateIntersection(strArr) {
let arrHalf1 = strArr[0].split(", ");
let arrHalf2 = strArr[1].split(", ");
let interArr = arrHalf1.filter(value => arrHalf2.includes(value));
let result = interArr.join();
if (result) {
return result;
} else {
return false;
}
}
My answer is a little flawed, but it should meet your requirements
function LocateIntersection(strArr) {
const AllArrHalf = strArr.map((value) => value.split(', ')).sort((a, b) => b.length - a.length);
const lastArrHalf = AllArrHalf[AllArrHalf.length - 1];
let interArr = [];
AllArrHalf.forEach((value, index) => {
if (index !== AllArrHalf.length - 1) {
interArr.push(lastArrHalf.filter(value1 => value.includes(value1)))
}
})
if (interArr.length > 1) {
let result = interArr.map(value => value.join(', '));
LocateIntersection(result);
} else if (interArr.length === 1) {
result = interArr.join();
console.log(result);
}
}
LocateIntersection(['a, b, c', 'a, b', 'a, b'])
You can try this.
const intersection = (arr1, arr2) => {
return arr2.filter(element => arr1.includes(element));
}
const getIntersection = (stringArray, prevResult) => {
const array1 = prevResult || stringArray[0].split(', ');
const array2 = stringArray.shift().split(', ');
const result = intersection(array1, array2);
console.log(`result : `, result)
if(result.length > 0 && stringArray.length > 0) {
return getIntersection(stringArray, result);
}
return result;
}
const input = ['1, 2','1, 3, 3, 3','123, 222','1, 1, 1','1','3, 2, 3, 1'];
const result = getIntersection(input);
console.log('final Result:',result);

How to test if an array contains arrays? (Jest)

Given the following function:
chunk = (arr, n) => {
return arr.reduce(function(p, cur, i) {
(p[i/n|0] = p[i/n|0] || []).push(cur);
return p;
}, []);
}
I want to test if the output array contains arrays:
test("Splits a given array in N arrays", () => {
let _input = Array.from({length: 999}, () => Math.floor(Math.random() * 999));;
let int = mockService.getRandomArbitrary();
expect(generalService.chunk(_input, int)).toContain(???????);
})
Considering matchers, how can one test if an array contains arrays?
Possibly something like this?
We use Array.isArray() (docs here) to test each element
let output = generalService.chunk(_input, int));
let containArrays = true;
if (output.length) {
output.forEach(element => {
// containArrays is false if one of the element is *not* an array
if (Array.isArray(element) === false) containArrays = false;
});
}
// if output is an empty array it doesn't contain arrays
else containArrays = false;
expect(containArrays).toBeTruthy();
If you use lodash it's very easy
_.any(arr,function(a){
return Array.isArray(a);
})

Count the occurences of the string in an array

Need to count the occurences of string in an array
userList=["abc#gmail.com","bca#gmail.com","abc#gmail.com"]
Need to get the count of each strings
let userList=["abc#gmail.com","bca#gmail.com","abc#gmail.com"]
Expected : [{"abc#gmail.com":2},{"bca#gmail.com":1}]
var userList=["abc#gmail.com","bca#gmail.com","abc#gmail.com"];
var result = Object.values(userList.reduce((acc, c)=>{
if(!acc.hasOwnProperty(c)) { acc[c] = {[c]:0};}
acc[c][c] += 1;
return acc;
}, {}));
console.log(result);
Hope this helps you !
You can use Array#reduce method with a reference object which keeps the index of the element.
let userList = ["abc#gmail.com", "bca#gmail.com", "abc#gmail.com"];
let ref = {};
let res = userList.reduce((arr, s) => (s in ref ? arr[ref[s]][s]++ : arr[ref[s] = arr.length] = { [s]: 1 }, arr), [])
console.log(res)
// or the same with if-else
// object for index referencing
let ref1 = {};
// iterate over the array
let res1 = userList.reduce((arr, s) => {
// check if index already defined, then increment the value
if (s in ref1)
arr[ref1[s]][s]++;
// else create new element and add index in reference array
else
arr[ref1[s] = arr.length] = { [s]: 1 };
// return array reference
return arr;
// set initial value as empty array for result
}, []);
console.log(res1)

Categories