Split String Every 2 Character into Array - javascript

I have a problem with my code. I have a series of string. For example I made this:
var a = 12345678
I want to split these string into an array, so that it will produce something like this:
[12,23,34,45,56,67,78]
I already tried this code:
var newNum = a.toString().match(/.{1,2}/g)
and it returns this result instead of the result I wanted
[12,34,56,78]
Are there any solution to this? Thanks in advance.

Shortest way:
'abcdefg'.split(/(..)/g).filter(s => s);
// Array(4) [ "ab", "cd", "ef", "g" ]
Explanation: split(/(..)/g) splits the string every two characters (kinda), from what I understand the captured group of any two characters (..) acts as a lookahead here (for reasons unbeknownst to me; if anyone has an explanation, contribution to this answer is welcome). This results in Array(7) [ "", "ab", "", "cd", "", "ef", "g" ] so all that's left to do is weed out the empty substrings with filter(s => s).

Hope this helps.
var a = 12345678;
a= a.toString();
var arr=[];
for (var i =0; i<a.length-1; i++) {
arr.push(Number(a[i]+''+a[i+1]));
}
console.log(arr);

You could use Array.from() like this:
let str = "12345678",
length = str.length - 1,
output = Array.from({ length }, (_,i) => +str.slice(i, i+2))
console.log(output)
Here's a generic solution for getting varying size of chunks:
function getChunks(number, size) {
let str = number.toString(),
length = str.length - size + 1;
return Array.from({ length }, (_,i) => +str.slice(i, i + size))
}
console.log(getChunks(12345, 3))
console.log(getChunks(12345678, 2))

We can do this using Array.reduce :
Firstly, convert the number into a string and then split it into an array
Secondly, apply reduce on the resulting array, then append current element ele with the next element only if the next element exists.
Lastly, after the append is done with the current and next element convert it back to a number by prefixing it with an arithmetic operator + and then add it to the accumulator array.
var a = 12345678;
const result = a.toString().split("").reduce((acc, ele, idx, arr) => {
return arr[idx + 1] ? acc.concat(+(ele + arr[idx + 1])) : acc;
}, []);
console.log(result);
console.assert(result, [12,23,34,45,56,67,78]);

Another approach, using reduce
var a = 12345678
a.toString()
.split('')
.reduce((c,x,i,A)=>i>0?c.concat([A[i-1]+A[i]]):c,[])

The pattern is start with the first two digits (12) and then add eleven until you have an array that ends with the last digit of the input string (8).
let str = `12345678`;
const eleven = string => {
let result = [];
let singles = string.split('');
let first = Number(singles.splice(0, 2).join(''));
for (let i = 0; i < string.length-1; i++) {
let next = 11 * i;
result.push(first+next);
}
return result;
}
console.log(eleven(str));

var a = 12345678;
console.log(
String(a)
.split("")
.map((value, index, array) => [value, array[index + 1]].join(''))
.map(item => Number(item))
);
output - [ 12, 23, 34, 45, 56, 67, 78, 8 ]
explanation
String(a) - convert your number value 'a' into string, to prepare for operations
split("") - convert string value into array
.map((value, index, array) => [value, array[index + 1]] ...
for every item from array, take current value and next value, and put them into array cell
.join('')) - then create string from this array value like this [ '1', '2' ] => ['12']
.map(item => Number(item)) - at the end, convert every array item into number.

You could use a recursive approach. Here I used an auxiliary function to perform the recursion, and the main function to convert the number to a string.
See example below:
const arr = 12345678;
const group = a => group_aux(`${a}`);
const group_aux = ([f, s, ...r]) =>
!s ? [] : [+(f+s), ...group_aux([s, ...r])];
console.log(group(arr));

My requirement is to convert a MD5 string (with length: 32) to a Uint8Array (with length: 16) as the key of AES algorithm. Reference from the post above, thanks.
var a = 'a12ab32fd78a89efa12ab32fd78a89ef';
var arr=[];
for (var i =0; i<a.length-1; i+=2) {
arr.push(parseInt(a[i]+''+a[i+1], 16));
}
console.log(arr.length);
console.log(arr);
console.log(new Uint8Array(arr));

If order doesn't matter, a more legible solution is:
let even = '12345678'.match(/(..)/g)
let odd = '2345678'.match(/(..)/g)
let result = [...even, ...odd]
If order does matter, just use .sort():
result.sort()

Related

JavaScript Trying to Print The Number of Times a Letter Appears In String But It Prints More than Once

In the code below, I am trying to check how many times a letter in a string appears. Problem with the code below is that it prints each letter more than once. It needs to collect all the same letters and show the number of times it occurs in the string and display it once.
const string = 'mississippi'
const letters = [...string]
let currentLetter = ''
let letterOccurance = []
for(let i = 0; i < letters.length; i++){
let letterFrequency = letters.filter((letter)=>{
return letter === letters[i]
})
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
}
console.log(letterOccurance)
That's too much code just to get the number of times a letter appears in a string. Try the following code:
const string = 'mississippi';
let frequency = {};
for (let letter of string) {
if (frequency[letter]) {
frequency[letter]++;
} else {
frequency[letter] = 1;
}
}
console.log(frequency);
You're always pushing the letter to the array, whether it already exists there or not:
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
You could check if it exists first:
if (!letterOccurance.find(l => l[0] === letters[i])) {
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
}
Or even skip it entirely if you've already seen it, since the first time you find any letter you already know its complete count:
for(let i = 0; i < letters.length; i++){
if (letterOccurance.find(l => l[0] === letters[i])) {
continue;
}
// the rest of the loop...
}
There's honestly a variety of ways you could step back and re-approach the problem. But for the question about why letters are repeating, that's simply because each iteration of the loop unconditionally appends the letter to the resulting array.
How about writing a more generic item-counting function and then layering countLetters as a simple partial application of the identity function?
const countBy = (fn) => ([...xs]) =>
xs .reduce ((a, x) => {const k = fn (x); a [k] = (a[k] || 0) + 1; return a}, {})
const countLetters = countBy (x => x)
console .log (countLetters ('missisippi'))
countBy is fairly generic. You pass it a function to convert your values to strings, and pass your array of items to the function it returns. Strings are array-like enough that this just works for our simple countLetters. But we could use it for other counts as well, such as:
countBy (x => x .grade) ([{id: 1, grade: 'A'}, {id: 2, grade: 'B'}, {id: 3, grade: 'A'}])
//=> {"A": 2, "B": 1}
Here's a solution using a Set to get the individual letters and String.split() to count.
const countChars = str => Object.fromEntries(
[...new Set(str)]
.map(c => [c, str.split(c).length-1])
)
console.log(countChars('mississippi'));
Using reduce to build the object
const countChars = str => [...str].reduce(
(a, c) => (a[c] ? a[c]++ : a[c]=1, a),
{}
)
console.log(countChars('mississippi'));
var result =

Repeat character depending on position in array + 1

I'm trying to get an output like this:
['h', 'ee', 'lll', 'llll', 'ooooo']
currently my out put is:
[ 'h', 'ee', 'lll', 'lll', 'ooooo' ]
The issue is the second occurrence of the "l" isn't being repeated one more time because I'm counting the index of the letter then adding 1 and it is only counting the first occurrence of the "l".
This is the code I have so far, any help would be great.
function mumble(string) {
string.toLowerCase();
let arrayPush = [];
let array = string.split("");
let count = 0;
let char = [];
array.map((letter) => {
count = array.indexOf(letter);
arrayPush.push(letter.repeat(count + 1));
});
return arrayPush;
}
console.log(mumble("hello"));
Don't use indexOf, use the second parameter in the .map callback to determine the index (and from that, the number of times to repeat the string).
function mumble(string) {
string.toLowerCase();
let arrayPush = [];
let array = string.split("");
let count = 0;
let char = [];
array.map((letter, i) => {
arrayPush.push(letter.repeat(i + 1));
});
return arrayPush;
}
console.log(mumble("hello"));
Instead of applying .map to an array split from the string, you can simply loop through the string, accessing each character using the .charAt() string method, and pushing it's .repeat() product to the result array.
Working snippet:
console.log(mumble('hELlo'));
function mumble(string) {
const result = [];
for(let i=0; i<string.length; i++) {
result.push(string.toLowerCase().charAt(i).repeat(i+1));
}
return result;
} // end function mumble;

Sort array by custom function in JavaScript

I am using only Javascript.
I have the following string :
?pn1=age&pn2=name&pv1=12&pv2=alice
What I need to do, is have the following outcome :
age:12|name:alice
I thought of a way to do this, it is the following :
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var strSplit = str.split("&");
for (var i = 0; i < strSplit.length; i++) {
console.log(strSplit[i]);
}
This returns the following result :
?pn1=age
pn2=name
pv1=12
pv2=alice
Since I want to join together pn1 and pv1 and pn2 and pv2, the number present in the end of the string is important.
?pn1=age
pn2=name
pv1=12
pv2=alice
So I thought a way to do this is to sort the array by this number. and then joining every 2 values together after sorting.
I tried the following code :
strSplit.sort(function() {
var pref = strSplit[i].split('=')[0];
return pref.charAt(pref.length-1);
});
It does not seem to work
Any help would be appreciated
You could split the parts, collect all items and return a joined string.
var string = '?pn1=age&pn2=name&pv1=12&pv2=alice',
result = string
.slice(1)
.split('&')
.reduce((r, p) => {
var [k, value] = p.split('='),
[key, index] = k.split(/(\d+)/);
index--;
r[index] = r[index] || {};
r[index][key] = value;
return r;
}, [])
.map(({ pn, pv }) => [pn, pv].join(':'))
.join('|');
console.log(result);
You can do that in following steps.
You can loop through half of the array and add corresponding keys and values to an array.
Consider i is the current index when we loop through half array.
The element at position i will be key.
Add the half of the length and add it to i to get corresponding value.
split() both key and value by = and get the second element.
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var arr = str.split("&");
let half = arr.length/2
let res = [];
for (var i = 0; i < half; i++) {
res.push(`${arr[i].split('=')[1]}:${arr[i + half].split('=')[1]}`);
}
console.log(res.join('|'))
You could use URLSearchParams to convert the query string to a collection of key-value pair.
Then loop through them to group the the pv and pn values based on the number.
Separate the string and and number values using the regex: (\D+)(\d+)
Loop through the obj.pn and get the corresponding pv value for the same number
Join the resulting array with |
This works with pn and pv values in any random order
const searchParams = new URLSearchParams("?pn1=age&pn2=name&pv1=12&pv2=alice")
const obj = { pn: {}, pv: {} }
for (let [key, value] of searchParams) {
const [, k, number] = key.match(/(\D+)(\d+)/)
obj[k][number] = value
}
const output = Object.entries(obj.pn)
.map(([n, key]) => `${key}:${obj.pv[n]}`)
.join("|")
console.log(output)
One idea is to first split values on & and add it to take digit as key and place on object and then later place the respective values in desired format
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice".replace(/^\?/,'')
var strSplit = str.split("&");
let op = strSplit.reduce((op,inp) => {
let [key,value] = inp.split('=')
let digit = key.match(/\d+/)[0]
op[digit] = op[digit] || []
op[digit].push(value)
return op
},{})
let final = Object.values(op).reduce((op,inp) => {
let [key,value] = inp
op.push(`${key}:${value}`)
return op
} ,[]).join(' | ')
console.log(final)
You could convert that & split to a string and remove the ?xxx= then split it again by , to finally have an array with the stuff you're looking at.
var str = "?pn1=age&pn2=name&pv1=12&pv2=alice";
var split = str.split('&').toString().replace(/([?]?[pnv0-9]+[=])/g,'').split(',');
console.log(split[0] + ':' + split[2] + '|' + split[1] + ':' + split[3]);
EDIT : worth mentioning for those who are looking to the best performing solution, I tested all those provided here, click here for more infos.
The solution's list from the fastest to the slowest :
Maheer Ali (113,610 ops/s ±1.48% fastest)
tcj (112,324 ops/s ±1.01% 1.13% slower)
Nina Scholz (81,067 ops/s ±1.81% 28.64% slower)
Code Maniac (80,074 ops/s ±0.99% 29.52% slower)
adiga (33,065 ops/s ±0.92% 70.9% slower)

Convert javascript string to array

I have string like this
'10:00','13:00','12:00','15:00','08:00','12:00'
I need it in format like this
Array(3)
Array[0] ['10:00', '13:00']
Array[1] ['12:00', '15:00']
Array[2] ['08:00', '12:00']
I tried with split method but without success.
You could replace single quotes with double quotes, add brackes and parse it as JSON and get an array, which is the grouped by two elements.
var string = "'10:00','13:00','12:00','15:00','08:00','12:00'",
array = JSON
.parse('[' + string.replace(/'/g, '"') + ']')
.reduce((r, s, i) => r.concat([i % 2 ? r.pop().concat(s) : [s]]), []);
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var str = "'10:00','13:00','12:00','15:00','08:00','12:00'";
var oldArray = str.split(',');
var newArray = [];
while(oldArray.length){
let start = 0;
let end = 2;
newArray.push(oldArray.slice(start, end));
oldArray.splice(start, end);
}
console.log(newArray);
How about:
"'10:00','13:00','12:00','15:00','08:00','12:00'"
.replace(/'/g, '').replace(/(,[^,]*),/g,"$1;")
.split(';').map(itm => itm.split(','))
In this case you want to compare 2 values.
To do this you can make a for loop that reads the current value and the last value and compares the two.
If the last value is higher than current value, the splitting logic happens.
Either you add the current value to the last item (which is an array of strings) in the results array or you add a new array of strings at the end of the results array.
One potential solution:
let S = "'10:00','13:00','12:00','15:00','08:00','12:00'";
let R = S.split(',');
let I = 0;
let A = new Array([],[],[]);
R.map((object, index) => {
A[I][index % 2] = R[index];
if (index % 2 == 1) I++;
});
console.log(A);
You can use String.split(',') to split into individual values, then group them based on their positions (result of integer division with 2).
I am using groupBy from 30 seconds of code (disclaimer: I am one of the maintainers of the project/website) to group the elements based on the integer division with 2. Short explanation:
Use Array.map() to map the values of an array to a function or property name. Use Array.reduce() to create an object, where the keys are produced from the mapped results.
The result is an object, but can be easily converted into an array using Object.values() as shown below:
var data = "'10:00','13:00','12:00','15:00','08:00','12:00'";
const groupBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
var arr = data.split(',');
arr = groupBy(arr, (v, i) => Math.floor(i / 2));
arr = Object.values(arr);
console.log(arr);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think use JSON.parse is better:
var array = "'10:00','13:00','12:00','15:00','08:00','12:00'";
array = JSON.parse( '[' + array.replace(/'/g,'"') + ']' );
var array2 = [];
for(var i=0;i < array.length - 1; i++){
array2.push([array[i], array[i+1]]);
}
console.log(array2);

Finding all indexes of a specified character within a string

For example, if I had "scissors" in variable and wanted to know the position of all occurrences of the letter "s", it should print out 1, 4, 5, 8.
How can I do this in JavaScript in most efficient way? I don't think looping through the whole is terribly efficient
A simple loop works well:
var str = "scissors";
var indices = [];
for(var i=0; i<str.length;i++) {
if (str[i] === "s") indices.push(i);
}
Now, you indicate that you want 1,4,5,8. This will give you 0, 3, 4, 7 since indexes are zero-based. So you could add one:
if (str[i] === "s") indices.push(i+1);
and now it will give you your expected result.
A fiddle can be see here.
I don't think looping through the whole is terribly efficient
As far as performance goes, I don't think this is something that you need to be gravely worried about until you start hitting problems.
Here is a jsPerf test comparing various answers. In Safari 5.1, the IndexOf performs the best. In Chrome 19, the for loop is the fastest.
Using the native String.prototype.indexOf method to most efficiently find each offset.
function locations(substring,string){
var a=[],i=-1;
while((i=string.indexOf(substring,i+1)) >= 0) a.push(i);
return a;
}
console.log(locations("s","scissors"));
//-> [0, 3, 4, 7]
This is a micro-optimization, however. For a simple and terse loop that will be fast enough:
// Produces the indices in reverse order; throw on a .reverse() if you want
for (var a=[],i=str.length;i--;) if (str[i]=="s") a.push(i);
In fact, a native loop is faster on chrome that using indexOf!
When i benchmarked everything it seemed like regular expressions performed the best, so i came up with this
function indexesOf(string, regex) {
var match,
indexes = {};
regex = new RegExp(regex);
while (match = regex.exec(string)) {
if (!indexes[match[0]]) indexes[match[0]] = [];
indexes[match[0]].push(match.index);
}
return indexes;
}
you can do this
indexesOf('ssssss', /s/g);
which would return
{s: [0,1,2,3,4,5]}
i needed a very fast way to match multiple characters against large amounts of text so for example you could do this
indexesOf('dddddssssss', /s|d/g);
and you would get this
{d:[0,1,2,3,4], s:[5,6,7,8,9,10]}
this way you can get all the indexes of your matches in one go
function charPos(str, char) {
return str
.split("")
.map(function (c, i) { if (c == char) return i; })
.filter(function (v) { return v >= 0; });
}
charPos("scissors", "s"); // [0, 3, 4, 7]
Note that JavaScript counts from 0. Add +1 to i, if you must.
In modern browsers matchAll do the job :
const string = "scissors";
const matches = [...string.matchAll(/s/g)];
You can get the values in several ways. For example :
const indexes = matches.map(match => match.index);
More functional fun, and also more general: This finds the starting indexes of a substring of any length in a string
const length = (x) => x.length
const sum = (a, b) => a+b
const indexesOf = (substr) => ({
in: (str) => (
str
.split(substr)
.slice(0, -1)
.map(length)
.map((_, i, lengths) => (
lengths
.slice(0, i+1)
.reduce(sum, i*substr.length)
))
)
});
console.log(indexesOf('s').in('scissors')); // [0,3,4,7]
console.log(indexesOf('and').in('a and b and c')); // [2,8]
indices = (c, s) => s
.split('')
.reduce((a, e, i) => e === c ? a.concat(i) : a, []);
indices('?', 'a?g??'); // [1, 3, 4]
Here is a short solution using a function expression (with ES6 arrow functions). The function accepts a string and the character to find as parameters. It splits the string into an array of characters and uses a reduce function to accumulate and return the matching indices as an array.
const findIndices = (str, char) =>
str.split('').reduce((indices, letter, index) => {
letter === char && indices.push(index);
return indices;
}, [])
Testing:
findIndices("Hello There!", "e");
// → [1, 8, 10]
findIndices("Looking for new letters!", "o");
// → [1, 2, 9]
Here is a compact (one-line) version:
const findIndices = (str, char) => str.split('').reduce( (indices, letter, index) => { letter === char && indices.push(index); return indices }, [] );
using while loop
let indices = [];
let array = "scissors".split('');
let element = 's';
let idx = array.indexOf(element);
while (idx !== -1) {
indices.push(idx+1);
idx = array.indexOf(element, idx + 1);
}
console.log(indices);
Another alternative could be using flatMap.
var getIndices = (s, t) => {
return [...s].flatMap((char, i) => (char === t ? i + 1 : []));
};
console.log(getIndices('scissors', 's'));
console.log(getIndices('kaios', '0'));
I loved the question and thought to write my answer by using the reduce() method defined on arrays.
function getIndices(text, delimiter='.') {
let indices = [];
let combined;
text.split(delimiter)
.slice(0, -1)
.reduce((a, b) => {
if(a == '') {
combined = a + b;
} else {
combined = a + delimiter + b;
}
indices.push(combined.length);
return combined; // Uncommenting this will lead to syntactical errors
}, '');
return indices;
}
let indices = getIndices(`Ab+Cd+Pk+Djb+Nice+One`, '+');
let indices2 = getIndices(`Program.can.be.done.in.2.ways`); // Here default delimiter will be taken as `.`
console.log(indices); // [ 2, 5, 8, 12, 17 ]
console.log(indices2); // [ 7, 11, 14, 19, 22, 24 ]
// To get output as expected (comma separated)
console.log(`${indices}`); // 2,5,8,12,17
console.log(`${indices2}`); // 7,11,14,19,22,24
Just for further solution, here is my solution:
you can find character's indexes which exist in a string:
findIndex(str, char) {
const strLength = str.length;
const indexes = [];
let newStr = str;
while (newStr && newStr.indexOf(char) > -1) {
indexes.push(newStr.indexOf(char) + strLength- newStr.length);
newStr = newStr.substring(newStr.indexOf(char) + 1);
}
return indexes;
}
findIndex('scissors', 's'); // [0, 3, 4, 7]
findIndex('Find "s" in this sentence', 's'); // [6, 15, 17]
function countClaps(str) {
const re = new RegExp(/C/g);
// matching the pattern
const count = str.match(re).length;
return count;
}
//countClaps();
console.log(countClaps("CCClaClClap!Clap!ClClClap!"));
Using recursion function:
let indcies=[];
function findAllIndecies(str,substr,indexToStart=0) {
if (indexToStart<str.length) {
var index= str.indexOf(substr,indexToStart)
indcies.push(index)
findAllIndecies(str,substr,index+1)
}
}
findAllIndecies("scissors","s")
You could probably use the match() function of javascript as well. You can create a regular expression and then pass it as a parameter to the match().
stringName.match(/s/g);
This should return you an array of all the occurrence of the the letter 's'.

Categories