# Find out whether string A can be shifted to get string B

Given two strings A and B, return whether or not A can be shifted some number of times to get B.

For example, if A is abcde and B is cdeab, return true. If A is abc and B is acb, return false.

Solution 1:

const haveSameLength = (a, b) => a.length === b.length;
const isSame = (a, b) => a === b;
const isFullyShifted = a => a === 0;
const shiftStringBy = i => a => ${a.substring(i)}${a.substring(0, i)};

const isSameAfterShifting = (strA, strB, items) => {
if (strA.length === 0 || strB.length ===0) { return false }
if (!haveSameLength(strA, strB)) { return false }
if (isSame(strA, strB)) { return true }
if (isFullyShifted(items)) { return false }

return isSameAfterShifting(strA, shiftStringBy(1)(strB), --items)
}

const str1 = 'abcde';
const str2 = 'cdeab';

console.log(isSameAfterShifting(str1, str2, str2.length));


Solution 2

const isSameAfterShifting2 = (strA, strB) => {
if (strA.length === 0 || strB.length ===0) { return false }
if (!haveSameLength(strA, strB)) { return false }
const arrB = strB.split('');
const firstLetterA = strA.substring(0, 1);

let shiftIndex = arrB.indexOf(firstLetterA);
if (shiftIndex === -1) { return false }
while (shiftIndex < arrB.length) {
const strBShifted = ${strB.substring(shiftIndex)}${strB.substring(0, shiftIndex)};
if (strA === strBShifted) { return true }
shiftIndex++;
}
return false;
}

console.log(isSameAfterShifting2('abc', 'acb'));


Which one is more readable and easier to understand for you?

• I think this needs only a one liner const isShifted = (a, b) => a.length === b.length && a === b || (a + a).includes(b); – Blindman67 Feb 12 at 21:15
• This is quite genius. Lol – thadeuszlay Feb 14 at 17:55

You can check if the String is empty with !str instead of strA.length === 0,

console.log(''); // false

i think haveSameLength and isSame are extras, you can write srtA.length === strB.length and it would still be readable,

you can get the first letter with a simpler strA[0] instead of strA.substring(0, 1);

Which one is more readable and easier to understand for you?

a loop is easier to read and understand than a recursive function,

But the hole approach seems like it can be simpler using a for loop, Array.some() , here's what i would suggest :

You can generate an array of combinations moving the letters one index at a time, for a string abc you would have ['abc, bca', 'cba'], see if one of the resulting array entries euqals the second string :

const isSameAfterShifting = (str1, str2) => {
// check if the strings are empty or has different lengths
if (!str1 || !str2 || str1.length !== str2.length) return false;

// check if the strings are the same
if (str1 === str2) return true;

// generate the array
let combos = [];
for (let i = 0; i < str1.length; i++) {
let c = str1.slice(i) + str1.slice(0, i);
combos.push(c);
}

// for a string 'abc'
// combos = ['abc', bca', 'cab']

// check if the array has one of its entries equal to the second string
return combos.some(s => s === str2);
}

console.log( isSameAfterShifting('abc', 'cab') );
console.log( isSameAfterShifting('abc', 'cabaaa') );
console.log( isSameAfterShifting('abc', 'bac') );

you can replace the for loop with Array.from()

const isSameAfterShifting = (str1, str2) => {
// check if the strings are empty or has different lengths
if (!str1 || !str2 || str1.length !== str2.length) return false;

// check if the strings are the same
if (str1 === str2) return true;

// generate the array
let combos = Array.from({
length: str1.length
}, (_, i) => str1.slice(i) + str1.slice(0, i));

// for a string 'abc'
// combos = ['abc', bca', 'cab']

// check if the array has one of its entries equal to the second string
return combos.some(s => s === str2);
};

console.log(isSameAfterShifting("abc", "cab"));
console.log(isSameAfterShifting("abc", "cabaaa"));
console.log(isSameAfterShifting("abc", "bac"));