Problem
Task: Take every 2nd char from the string, then the other chars, that are not every 2nd char, and concat them as new String.
Do this n times!
Examples:
"This is a test!", 1 -> "hsi etTi sats!"
"This is a test!", 2 -> "hsi etTi sats!" -> "s eT ashi tist!"
Code:
const split = (text) => {
const firstPart = text.split('').filter((element, index) => index % 2 != 0).join('')
const secondPart = text.split('').filter((element, index) => index % 2 == 0).join('')
return firstPart + secondPart
}
const encrypt = (text, n) => {
if (text == null) {
return null
}
let result = text
for (let i = 0; i < n; i++) {
result = split(result)
}
return result
}
const decrypt = (text, n) => {
if (text == null) {
return null
}
for (let i = 0; i < n; i++) {
let firstPartLength = text.length % 2 == 0 ? text.length / 2 : (text.length - 1) / 2 + 1
let secondPartLenght = text.length % 2 == 0 ? text.length / 2 : (text.length - 1) / 2
let firstPart = text.substring(0, firstPartLength)
let secondPart = text.substring(secondPartLenght, text.length)
secondPart = secondPart.split('').map(element => element + ' ').join('')
let position = -1
secondPart = secondPart.split('').map((element, index) => index % 2 != 0 ? firstPart[++position] : element).join('').substring(0, text.length)
text = secondPart
}
return text
}
console.log(decrypt(encrypt('This is a test!', 3), 3))
console.log(encrypt('Some text!', 4))
Solution
Here’s a declarative take on it:
const is2ndChar = (c, i) => i % 2;
const isNot2ndChar = (c, i) => !(i % 2)
const scramble = s =>
s.split('').filter(is2ndChar)
.concat(s.split('').filter(isNot2ndChar))
.join('');
const test1 = scramble('This is a test!');
const test2 = scramble(scramble('This is a test!'));
console.log(test1, test1 === 'hsi etTi sats!');
console.log(test2, test2 === 's eT ashi tist!');
The filter-functions are only used once each, so they could just go directly into filter
, but it’s a little more legible this way.
const split = (text) => (text.replace(/.(.)?/g, '$1') + ("d"+text).replace(/.(.)?/g, '$1')
The regex matches every other char. Do it twice, add any arbitrary char to the start of the string the second time to offset it.
- Modification on the split function should be a little more efficient since you only go through the variable once.
- Added join function using similar logic as split. Again, should be more efficient.
- Removed
let result = text
in the encrypt function and used text. No need to create an extra variable here.
const split = (text) => {
let n = Math.floor(text.length / 2)
return text.split('').reduce((a, v, i) => {
a[i % 2 ? (i - 1) / 2 : n + (i / 2)] = v
return a
}, []).join('')
}
const join = (text) => {
let n = Math.floor(text.length / 2)
return text.split('').reduce((a, v, i) => {
a[i < n ? (i + 1) * 2 - 1 : (i - n) * 2] = v
return a
}, []).join('')
}
const encrypt = (text, n) => {
if (text == null) {
return null
}
for (let i = 0; i < n; i++) {
text = split(text)
}
return text
}
const decrypt = (text, n) => {
if (text == null) {
return null
}
for (let i = 0; i < n; i++) {
text = join(text)
}
return text
}
console.log(decrypt(encrypt('This is a test!', 3), 3))
console.log(encrypt('Some text!', 4))