2

My case is to separate a string into array of strings and then convert every three characters into a string. ( e.g. "xxxyyy" -> ['xxx','yyy'] )

const translate = function (RNA) {
    var arrRna = Array.from(RNA);
    var arr = [];
    for (var key in arrRna) {
        if ((key % 3) == 0) {
            var temp = RNA.slice( key,  (key+3));
            arr.push(temp);
        }

    }
    return arr;
}

console.log(translate('xxxyyyzzz'));

Expected result : ['xxx','yyy','zzz']

But the result that I want is : [ 'xxx', 'yyyzzz', 'zzz' ]

Also, I noticed that the slice method works as expected in first iteration but after that, the weird result --> 'yyyzzz'. Why??

1
  • 4
    You shouldn't use for...in loops on arrays, that's generally unreliable given the (unfortunately) common practice of adding enumerable methods to built-in types (and the fact that the keys are strings instead of numbers as pointed out in the answer below). Commented Dec 25, 2018 at 19:02

6 Answers 6

6

The issue is that for..in loops over property names, and property names are always strings. So, for example, when key is 3:

var temp = RNA.slice( key,  (key+3));

evaluates to

var temp = RNA.slice('3',  '33');

because + concatenates when strings are involved. You might cast to Number first:

const translate = function(RNA) {
  var arrRna = Array.from(RNA);
  var arr = [];
  for (var key in arrRna) {
    key = Number(key);
    if ((key % 3) == 0) {
      var temp = RNA.slice(key, (key + 3));
      arr.push(temp);
    }

  }
  return arr;
}

console.log(translate('xxxyyyzzz'));

Or, you might chunk the array using a plain for loop, whose logic might be easier to understand at a glance:

const translate = function(RNA) {
  const output = [];
  for (let i = 0; i < RNA.length; i += 3) {
    output.push(RNA.slice(i, i + 3));
  }
  return output;
}

console.log(translate('xxxyyyzzz'));

Another option would be to use a global regular expression .match:

const translate = RNA => RNA.match(/.{1,3}/g);
console.log(translate('xxxyyyzzz'));

Sign up to request clarification or add additional context in comments.

1 Comment

you are god like, the regex solution is interesting
5

Tada! Rather than converting the string to an array and going through each character waiting for the index to be a multiple of 3, simply count by 3s.

function translate(rna) {
  let arr = [];
  
  for (let i = 0; i < rna.length; i += 3) {
    arr.push(rna.slice(i, i + 3));
  }
  
  return arr;
}

console.log(translate('xxxydyyzzzd'));

Comments

1

Approach using Array.from() with mapping callback to do whole process

const translate = (RNA) => {
  return Array.from({length: Math.ceil(RNA.length/3)}, (_,i)=> RNA.slice(i*3, i*3+3));       
}

console.log(translate('xxxyyyzzz'));

Comments

0

Hey so I figured out the problem. When you add 3 to the key, it concatenantes the result to give you 0, 03, 3, 33, 6, 63 as key and key+3 giving you the result you see.

const translate = function (RNA) {
    var arrRna = Array.from(RNA);
    var arr = [];
    for (var key in arrRna) {
        if ((key % 3) == 0) {
            console.log(key)
            console.log(key+3)
            var temp = RNA.slice( key,  (key+3));
            arr.push(temp);
        }

    }
    return arr;
}

console.log(translate('xxxyyyzzz'));

The solution is simple. Add a '+' before key. This type casts it to numeric giving you the expected result.

const translate = function (RNA) {
    var arrRna = Array.from(RNA);
    var arr = [];
    for (var key in arrRna) {
        if ((key % 3) == 0) {
            var temp = RNA.slice( +key,  (+key+3));
            arr.push(temp);
        }

    }
    return arr;
}

console.log(translate('xxxyyyzzz'));

Comments

0

Beside the adding a number to a string, which keys of objects are, you could take a generator for an arbitrary slicing of strings.

function* translate (string, size) {
    var i = 0;
    while (i < string.length) yield string.slice(i, i += size);
}

console.log([...translate('xxxyyyzzz', 3)]);

Comments

0

Sharing one more solution independent of no of characters(3)

let spltStr = myStr =>
  [...myStr.toLowerCase()].reduce((acc, char) => {
    let last = acc[acc.length - 1];
    !last || last[last.length - 1] !== char
      ? acc.push(char)
      : (acc[acc.length - 1] += char);
    return acc;
  }, []);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.