'How to write a function that returns true if a portion of str1 can be rearranged to str2?

I am having trouble with below question. I basically have to write a code/function that returns true if a portion of str1 can be rearraged to str2.

Write function scramble(str1,str2) that returns true if a portion of str1 characters can be rearranged to match str2, otherwise returns false.

For example: str1 is 'rkqodlw' and str2 is 'world' the output should return true. str1 is 'cedewaraaossoqqyt' and str2 is 'codewars' should return true. str1 is 'katas' and str2 is 'steak' should return false.

Only lower case letters will be used (a-z). No punctuation or digits will be included. Performance needs to be considered.

Below is the current code I have:

function scramble(str1, str2) {
  var first; //longer string
  var second; //shorter string

  if(str1 || str2 === "undefined") {
    return false;
  }

  if(str1.length > str2.length) {
    first = str1;
    second = str2
  } else if(str2.length > str1.length) {
    first = str2;
    second = str1;
  }

  for (i=0; i<second.length; i++) {
    if (first.indexOf(second[i]) === -1) {
      return false;
    }
  }

  return true;

}

Could you please help me with this question?



Solution 1:[1]

You could use a hash table with the count of the letters and check with count and decrement the count.

This proposal does not mutate the arrays.

function scramble(str1, str2) {
    var count = Object.create(null);

    Array.prototype.forEach.call(str1, function(a) {
        count[a] = (count[a] || 0) + 1;
    });

    return Array.prototype.every.call(str2, function(a) {
        return count[a]--;
    });
}

console.log(scramble('rkqodlw', 'world'));              // true
console.log(scramble('cedewaraaossoqqyt', 'codewars')); // true
console.log(scramble('katas', 'steak'));                // false
console.log(scramble('', 'o'));                // false

Solution 2:[2]

Here is the function with some tests:

function scramble(str1, str2) {
  var l = str2.length;
  for (var i = 0; i < l; i++) {
    if (str1.indexOf(str2[i]) > -1) {
      str1 = str1.replace(str2[i], '');
    } else {
      return false;
    }
  }
  return true;
}

function test(str1, str2) {
  console.log('testing "'+str1+'" w/ "'+str2+'": '+(scramble(str1, str2) ? 'true' : 'false'));
}

test('rkqodlw', 'world');
test('cedewaraaossoqqyt', 'codewars');
test('katas', 'steak');

The tests are returning:

testing "rkqodlw" w/ "world": true
testing "cedewaraaossoqqyt" w/ "codewars": true
testing "katas" w/ "steak": false

The function checks if every char of str2 is in str1 and removes it from str1 so that a char from str1 doesn't count twice.

Solution 3:[3]

Split the strings into arrays, and check if every character in the second array is inside the first array.

You probably want to splice of characters as you go, to account for mulitiples of the same character

function scramble(str1, str2) {
    var [arr1, arr2] = [str1.split(''), str2.split('')];
    return arr2.every(x=>arr1.indexOf(x)===-1?false:arr1.splice(arr1.indexOf(x),1));
}

console.log( scramble('rkqwodlw', 'world') );     // true
console.log( scramble('mgoaon', 'moon') );        // true
console.log( scramble('oijhnnassduda', 'moon') ); // false, only one "o"
console.log( scramble('test', 'unicorn') );       // false

Solution 4:[4]

function scramble(str1, str2) {
var [a,b,c] = [str1.split(''),str2.split(''),[]];
for (let i = 0; i < b.length; i++) {
    if (a.indexOf(b[i]) !== -1) {c.push(b[i]), a.splice(a.indexOf(b[i]), 1);}
}
return b.join('') === c.join('');}

Solution 5:[5]

I used hash table for good performance:

(There is a similar solution that has already been posted, but this solution in my opinion has a better performance.)

function scramble(str1, str2) {
  var hash = [];
  for (var i = 0; i < 26; i++) {
    hash.push(0);
  }
  for (let i of str1) {
    hash[i.charCodeAt(0)-97]++;
  }

  for (let i of str2) {
    if(hash[i.charCodeAt(0)-97] === 0) {
      return false;
    }
    hash[i.charCodeAt(0)-97]--;
  }
  return true;
}

console.log(scramble('rkqodlw','world')) //true
console.log(scramble('cedewaraaossoqqyt','codewars')) //true
console.log(scramble('katas','steak')) //false
console.log(scramble('scriptjavx','javascript')) //false
console.log(scramble('scriptingjava','javascript')) //true
console.log(scramble('scriptsjava','javascripts')) //true
console.log(scramble('javscripts','javascript')) //false
console.log(scramble('jscripts','javascript')) //false
console.log(scramble('aabbcamaomsccdd','commas')) //true
console.log(scramble('commas','commas')) //true
console.log(scramble('sammoc','commas')) //true

Solution 6:[6]

function scramble(str1, str2) {
    if(chckCode(str1) && chckCode(str2) ){
        return str2.split("").every(char => str1.includes(char))
    }else{
        return false
    }
}
function chckCode(str){
    return str.split("").every((chr,index) => {
        let code = str.charCodeAt(index);
        if((97 <= code && code <= 122)){
            return true;
        }else{
            return false;
        }
    })
}

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 FirePanther
Solution 3
Solution 4 Elias Felvinczi
Solution 5 Malachi Waisman
Solution 6 jrswgtr