'How to symmetrically split a string in JavaScript?
I am trying to symmetrically split a string in JavaScript. By that I mean, if it is 8 characters, then divide it into chunks of 2. If it is 9 characters, into chunks of 3. If it is n characters, divide it into chunks of 2 and 3 so that it forms a mirror image in the center.
const segmentNumber = (value) => {
let array = value.split('')
if (array.length % 3 === 0) {
return chunkArray(array, 3).join('·')
} else if (array.length % 2 === 0) {
return chunkArray(array, 2).join('·')
} else {
let reversed = array.slice().reverse()
let a = 0
let ar = []
let zr = []
while (true) {
ar.push(array.slice(a, a + 2).join(''))
zr.push(reversed.slice(a, a + 2).join(''))
array = array.slice(a + 2)
reversed = reversed.slice(a + 2)
a += 2
let modulus
if (array.length % 3 === 0) {
modulus = 3
} else if (array.length % 2 === 0) {
modulus = 2
}
if (modulus) {
return ar.concat(chunkArray(array, modulus)).concat(zr.reverse())
}
}
}
return
}
function chunkArray(arr, len) {
var chunks = [],
i = 0,
n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
I can chunk the string but not sure how to make it symmetrically chunked. For example:
- 10: 2-3-3-2
- 11: 2-2-3-2-2
- 12: 3-3-3-3
- 13: 2-3-3-3-2
How do you generate this sort of pattern, where the smaller numbers are on the outside, and the bigger number 3 is toward the center, so it forms a mirror image?
How do I improve what I am sort of implementing?
Solution 1:[1]
This will produce pattern for numbers greater than 6, and always have at least one '2' on the outside (except 9)
const splitter = n => {
if (n < 7) {
throw 'bad'
}
let twos = 0;
let threes = Math.ceil(n / 3);
// 9 is an edge case
if (n !== 9) {
let remain;
do {
--threes;
remain = n - threes * 3;
} while (remain % 4);
if (threes < 0) {
threes = n / 3;
remain = 0;
}
twos = remain / 4;
}
return `${'2'.repeat(twos)}${'3'.repeat(threes)}${'2'.repeat(twos)}`.split('');
}
for (let i = 7; i < 50; ++i) console.log(i, splitter(i).join('-'))
hmmm, I see you don't have 2's in all your cases
Simple change ...
const splitter = n => {
if (n < 7) {
throw 'bad'
}
let twos = 0;
let threes = Math.floor(n / 3) + 1;
// 9 is an edge case
let remain;
do {
--threes;
remain = n - threes * 3;
} while (remain % 4);
if (threes < 0) {
threes = n / 3;
remain = 0;
}
twos = remain / 4;
return `${'2'.repeat(twos)}${'3'.repeat(threes)}${'2'.repeat(twos)}`.split('');
}
for (let i = 7; i < 50; ++i) console.log(i, splitter(i).join('-'))
Solution 2:[2]
function segmentNumber(value)
{
for (let i = 0; i <= value; i++)
{
d = (value - 3 * i)/4
if (d >= 0 && d == parseInt(d))
{
return Array(d).fill(2).concat(Array(i).fill(3), Array(d).fill(2))
}
}
}
Solution 3:[3]
Does this meet your output? I am not sure with what your inputs are so I have only tested it on the sample values you provided instead.
function segmentNumber(length) {
let outside = 0;
if (length < 6)
return 'Only 6 and greater';
if(length % 3 == 0)
return new Array(length / 3).fill(3).join('-');
else {
while(length % 3 != 0 && length > 6) {
outside++;
length = length - 4;
}
if(length == 4)
return new Array(Math.floor(++outside * 2)).fill(2).join('-');
else
return [...new Array(outside).fill(2),
...new Array(Math.floor(length / 3)).fill(3),
...new Array(outside).fill(2)].join('-');
}
}
console.log(segmentNumber(10))
console.log(segmentNumber(11))
console.log(segmentNumber(12))
console.log(segmentNumber(13))
Solution 4:[4]
Criteria
From what I gathered from the OP and comments, the objective is return a symmetrical series of 2s and 3s from a given integer. So here's a few criteria I tried to follow:
From the start and end of the result are the 2s then the 3s are positioned up to the center:
10 => 2 3 3 2Numbers that shouldn't be accepted are numbers lower than 4 and 5 as well. So a limit will be set for anything less than 6 (4 is symmetrical but I didn't want to write extra code to include it)
If the given number is odd, it will have a 3 in the center.
11 => 2 2 3 2 2A symmetrical pattern only needs one half of a pattern to be built so divide the number by 2 (if odd parity subtract 3 before dividing by 2).
if (int < 6) return "Must be an integer greater than 5"; let parity = int & 1 ? 'odd' : 'even'; if (parity === 'odd') { int = int - 3; } side = int / 2;Find how many iterations are needed to divide the number by 3 and then the remaining (if any) by 2.
The remaining number can only be a 4, 2, or 0 in order to maintain symmetry. If the remaining number is 1, then the total number of iterations to divide by 3 should be one less and the remaining number 1 will be a 4.
Two separate loops to run division by 3 and division by 2.
let temp = Math.floor(side / 3); let rem = side % 3; if (rem === 1) { temp = temp - 1; rem = 4; } for (let i = 0; i < temp; i++) { result.push(3); } for (let i = 0; i < rem / 2; i++) { result.push(2); }Next, make a copy of the
resultarray with.slice(0)and.reverse()it. Ifparitywas"odd"thenunshift(3)to the front ofresult. Finally.concat()the reversed array in front of theresultarray, and then.join(' ')it into a string.const left = result.slice(0).reverse(); if (parity === 'odd') { result.unshift(3); } return left.concat(result).join(' ');
// Utility function
const log = (data, str = true) => {
if (!str) return console.log(data);
return console.log(JSON.stringify(data));
}
const x23 = int => {
let result = [];
let side, odd;
if (int < 6) return "Must be an integer greater than 5";
let parity = int & 1 ? 'odd' : 'even';
if (parity === 'odd') {
int = int - 3;
}
side = int / 2;
let temp = Math.floor(side / 3);
let rem = side % 3;
if (rem === 1) {
temp = temp - 1;
rem = 4;
}
for (let i = 0; i < temp; i++) {
result.push(3);
}
for (let i = 0; i < rem / 2; i++) {
result.push(2);
}
const left = result.slice(0).reverse();
if (parity === 'odd') {
left.push(3);
}
return left.concat(result).join(' ');
}
log('5: '+x23(5));
log('6: '+x23(6));
log('7: '+x23(7));
log('8: '+x23(8));
log('9: '+x23(9));
log('10: '+x23(10));
log('11: '+x23(11));
log('12: '+x23(12));
log('13: '+x23(13));
log('14: '+x23(14));
log('15: '+x23(15));
log('16: '+x23(16));
log('17: '+x23(17));
log('18: '+x23(18));
log('19: '+x23(19));
log('20: '+x23(20));
log('21: '+x23(21));
log('22: '+x23(22));
log('23: '+x23(23));
log('24: '+x23(24));
log('53: '+x23(53));
log('99: '+x23(99));
.as-console-wrapper {
min-height: 100% !important;
}
Solution 5:[5]
Try this.
const _0 = function(_0) {
_0 += '';
if (typeof _0[5] === 'undefined') {
return false;
}
let _1 = _0.length;
let _2 = _1;
let _3 = 2;
let _4 = 3;
if ((_1 & 1) === 0) {
_4 = 0;
}
let _5 = [];
let _6 = [];
let _7 = 0;
let _8 = 0;
while (_2 !== _4) {
_7 = _2 / 3;
_7 = (_7 | 0) === _7 - 0;
_3 = 2 + _7;
_2 -= _3 << 1;
_5[_8] = _3;
_6[_8++] = '';
_5[_8] = _3;
_6[_8++] = '';
}
_2 = _5.length;
_3 = _2 - 1;
if ((_1 & 1) === 1) {
_3++;
_5[_8] = 3;
_6[_8] = '';
}
_7 = 0;
_8 = 0;
_9 = 0;
let _10 = 0;
let _11 = 0;
while (_7 !== _2) {
_8 = _5[_7 + 1];
_9 = 0;
_1 -= _8;
while (_9 !== _8) {
_6[_10] += _0[_11 + _9];
_6[_3] += _0[_1 + _9++];
}
_3--;
_7 += 2;
_10++;
_11 += _8;
}
if (_6[_10] === '') {
_2 = 0;
if (_0[_7] === _6[_10 - 1][_8 - 1]) {
_7++;
}
while (_2 !== 3) {
_6[_10] += _0[_7 + _2++];
}
}
return _6.join('-');
}
console.log(_0('abcde'));
console.log(_0('abcdef'));
console.log(_0('abcdefg'));
console.log(_0('abcdefgh'));
console.log(_0('abcdefghi'));
console.log(_0('abcdefghij'));
console.log(_0('abcdefghijk'));
This is the fastest answer by avoiding unnecessary math and conditional statements in each loop.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | |
| Solution 5 |
