Find all letter Combinations of a Phone NumberAlgorithm to Iterate All Possible Strings in ClojureLetter combinations of phone dial pad numberLeetcode 17. Letter Combinations of a Phone NumberFind number of combinations of stringsListing all possible names from a phone numberDecode the Morse CodeFinding all possible letter combinations from an inputted phone numberPrint out all possible letter combinations a given phone number can representFind index of the nearest larger number of a numberFind the smallest distance between any two given words in a string

Why did Intel abandon unified CPU cache?

Can you make an identity from this product?

A life of PhD: is it feasible?

Proving that a Russian cryptographic standard is too structured

Remove border lines of SRTM tiles rendered as hillshade

Part of my house is inexplicably gone

Do you have to have figures when playing D&D?

Are the guests in Westworld forbidden to tell the hosts that they are robots?

If someone intimidates another person, does the person affected gain the Frightened condition?

Can there be absolute velocity?

Why is long-term living in Almost-Earth causing severe health problems?

A Salute to Poetry

Should I refuse to be named as co-author of a low quality paper?

How to avoid typing 'git' at the begining of every Git command

As easy as Three, Two, One... How fast can you go from Five to Four?

Housemarks (superimposed & combined letters, heraldry)

Is Jesus the last Prophet?

YA book about blind creatures that live underground and take kid's eyes

The origin of the Russian proverb about two hares

Grandpa has another non math question

Print "N NE E SE S SW W NW"

I've been given a project I can't complete, what should I do?

How do you play "tenth" chords on the guitar?

Confused with atmospheric pressure equals plastic balloon’s inner pressure



Find all letter Combinations of a Phone Number


Algorithm to Iterate All Possible Strings in ClojureLetter combinations of phone dial pad numberLeetcode 17. Letter Combinations of a Phone NumberFind number of combinations of stringsListing all possible names from a phone numberDecode the Morse CodeFinding all possible letter combinations from an inputted phone numberPrint out all possible letter combinations a given phone number can representFind index of the nearest larger number of a numberFind the smallest distance between any two given words in a string






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








3












$begingroup$


The task



is taken from LeetCode




Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A
mapping of digit to letters (just like on the telephone buttons) is
given below. Note that 1 does not map to any letters.



enter image description here



Example:



Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].


Note:



Although the above answer is in lexicographical order, your answer could be in any order you want.




My solution



(I've been told I should provide additional information to my solution otherwise I get downvoted.)



is based on backtracking. Why I choosed that approach? Well, whenever you encounter a task where you have to combine or permutate things, then backtracking is a possible approach.



But if you know a better one, then please go ahead. Otherwise I only got generic questions to my code: Can you make it faster, cleaner, more readable, etc.?



Also I'm interested in functional programming. So, if you got a good functional approach, feel free to post it here, too. Other than that, I'm always interested in a different perspective. So, if you got a fancy or conservative approach, please feel free to post them here.



Imperative approach



/**
* @param string digits
* @return string[]
*/
var letterCombinations = function(digits)
if (digits === '') return [];
const strDigits =
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz',
;

if (digits.length === 1) return [...strDigits[digits]];
const res = [];
const combine = (cur, n) =>
if (cur.length === digits.length)
res.push(cur);
return;


[...strDigits[digits[n]]].forEach(x =>
combine(cur + x, n + 1);
);

;

combine('', 0);
return res;
;


Functional approach



/**
* @param string digits
* @return string[]
*/
var letterCombinations = function(digits)
if (digits === '') return [];

const strDigits =
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz',
;

const combine = (cur, n) => cur.length === digits.length
? cur
: [...strDigits[digits[n]]].flatMap(x => combine(cur + x, n + 1));

return combine('', 0);
;









share|improve this question











$endgroup$


















    3












    $begingroup$


    The task



    is taken from LeetCode




    Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A
    mapping of digit to letters (just like on the telephone buttons) is
    given below. Note that 1 does not map to any letters.



    enter image description here



    Example:



    Input: "23"
    Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].


    Note:



    Although the above answer is in lexicographical order, your answer could be in any order you want.




    My solution



    (I've been told I should provide additional information to my solution otherwise I get downvoted.)



    is based on backtracking. Why I choosed that approach? Well, whenever you encounter a task where you have to combine or permutate things, then backtracking is a possible approach.



    But if you know a better one, then please go ahead. Otherwise I only got generic questions to my code: Can you make it faster, cleaner, more readable, etc.?



    Also I'm interested in functional programming. So, if you got a good functional approach, feel free to post it here, too. Other than that, I'm always interested in a different perspective. So, if you got a fancy or conservative approach, please feel free to post them here.



    Imperative approach



    /**
    * @param string digits
    * @return string[]
    */
    var letterCombinations = function(digits)
    if (digits === '') return [];
    const strDigits =
    '2': 'abc',
    '3': 'def',
    '4': 'ghi',
    '5': 'jkl',
    '6': 'mno',
    '7': 'pqrs',
    '8': 'tuv',
    '9': 'wxyz',
    ;

    if (digits.length === 1) return [...strDigits[digits]];
    const res = [];
    const combine = (cur, n) =>
    if (cur.length === digits.length)
    res.push(cur);
    return;


    [...strDigits[digits[n]]].forEach(x =>
    combine(cur + x, n + 1);
    );

    ;

    combine('', 0);
    return res;
    ;


    Functional approach



    /**
    * @param string digits
    * @return string[]
    */
    var letterCombinations = function(digits)
    if (digits === '') return [];

    const strDigits =
    '2': 'abc',
    '3': 'def',
    '4': 'ghi',
    '5': 'jkl',
    '6': 'mno',
    '7': 'pqrs',
    '8': 'tuv',
    '9': 'wxyz',
    ;

    const combine = (cur, n) => cur.length === digits.length
    ? cur
    : [...strDigits[digits[n]]].flatMap(x => combine(cur + x, n + 1));

    return combine('', 0);
    ;









    share|improve this question











    $endgroup$














      3












      3








      3





      $begingroup$


      The task



      is taken from LeetCode




      Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A
      mapping of digit to letters (just like on the telephone buttons) is
      given below. Note that 1 does not map to any letters.



      enter image description here



      Example:



      Input: "23"
      Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].


      Note:



      Although the above answer is in lexicographical order, your answer could be in any order you want.




      My solution



      (I've been told I should provide additional information to my solution otherwise I get downvoted.)



      is based on backtracking. Why I choosed that approach? Well, whenever you encounter a task where you have to combine or permutate things, then backtracking is a possible approach.



      But if you know a better one, then please go ahead. Otherwise I only got generic questions to my code: Can you make it faster, cleaner, more readable, etc.?



      Also I'm interested in functional programming. So, if you got a good functional approach, feel free to post it here, too. Other than that, I'm always interested in a different perspective. So, if you got a fancy or conservative approach, please feel free to post them here.



      Imperative approach



      /**
      * @param string digits
      * @return string[]
      */
      var letterCombinations = function(digits)
      if (digits === '') return [];
      const strDigits =
      '2': 'abc',
      '3': 'def',
      '4': 'ghi',
      '5': 'jkl',
      '6': 'mno',
      '7': 'pqrs',
      '8': 'tuv',
      '9': 'wxyz',
      ;

      if (digits.length === 1) return [...strDigits[digits]];
      const res = [];
      const combine = (cur, n) =>
      if (cur.length === digits.length)
      res.push(cur);
      return;


      [...strDigits[digits[n]]].forEach(x =>
      combine(cur + x, n + 1);
      );

      ;

      combine('', 0);
      return res;
      ;


      Functional approach



      /**
      * @param string digits
      * @return string[]
      */
      var letterCombinations = function(digits)
      if (digits === '') return [];

      const strDigits =
      '2': 'abc',
      '3': 'def',
      '4': 'ghi',
      '5': 'jkl',
      '6': 'mno',
      '7': 'pqrs',
      '8': 'tuv',
      '9': 'wxyz',
      ;

      const combine = (cur, n) => cur.length === digits.length
      ? cur
      : [...strDigits[digits[n]]].flatMap(x => combine(cur + x, n + 1));

      return combine('', 0);
      ;









      share|improve this question











      $endgroup$




      The task



      is taken from LeetCode




      Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. A
      mapping of digit to letters (just like on the telephone buttons) is
      given below. Note that 1 does not map to any letters.



      enter image description here



      Example:



      Input: "23"
      Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].


      Note:



      Although the above answer is in lexicographical order, your answer could be in any order you want.




      My solution



      (I've been told I should provide additional information to my solution otherwise I get downvoted.)



      is based on backtracking. Why I choosed that approach? Well, whenever you encounter a task where you have to combine or permutate things, then backtracking is a possible approach.



      But if you know a better one, then please go ahead. Otherwise I only got generic questions to my code: Can you make it faster, cleaner, more readable, etc.?



      Also I'm interested in functional programming. So, if you got a good functional approach, feel free to post it here, too. Other than that, I'm always interested in a different perspective. So, if you got a fancy or conservative approach, please feel free to post them here.



      Imperative approach



      /**
      * @param string digits
      * @return string[]
      */
      var letterCombinations = function(digits)
      if (digits === '') return [];
      const strDigits =
      '2': 'abc',
      '3': 'def',
      '4': 'ghi',
      '5': 'jkl',
      '6': 'mno',
      '7': 'pqrs',
      '8': 'tuv',
      '9': 'wxyz',
      ;

      if (digits.length === 1) return [...strDigits[digits]];
      const res = [];
      const combine = (cur, n) =>
      if (cur.length === digits.length)
      res.push(cur);
      return;


      [...strDigits[digits[n]]].forEach(x =>
      combine(cur + x, n + 1);
      );

      ;

      combine('', 0);
      return res;
      ;


      Functional approach



      /**
      * @param string digits
      * @return string[]
      */
      var letterCombinations = function(digits)
      if (digits === '') return [];

      const strDigits =
      '2': 'abc',
      '3': 'def',
      '4': 'ghi',
      '5': 'jkl',
      '6': 'mno',
      '7': 'pqrs',
      '8': 'tuv',
      '9': 'wxyz',
      ;

      const combine = (cur, n) => cur.length === digits.length
      ? cur
      : [...strDigits[digits[n]]].flatMap(x => combine(cur + x, n + 1));

      return combine('', 0);
      ;






      javascript algorithm programming-challenge functional-programming






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 8 hours ago







      thadeuszlay

















      asked 8 hours ago









      thadeuszlaythadeuszlay

      1,617718




      1,617718




















          2 Answers
          2






          active

          oldest

          votes


















          4












          $begingroup$


          whenever you encounter a task where you have to combine or permute things, then backtracking is a possible approach.




          True. It is not necessarily the best though (in fact it is rarely the best).



          In this particular case, the problem naturally maps to finding the next combination. In turn, it is no more than an increment of a number in some fancy numbering system. In your example, the minimal possible string is ad. Subsequent increments yield ae, then af, then ('f' + 1 is d and a carry bit does carry) bd, etc.



          Consider implementing the increment/next method directly. The space complexity will definitely benefit; and it is trivial to convert into a generator. The time complexity is likely to also benefit, depending on the use case.



          PS: thank you for posting your train of thoughts.






          share|improve this answer









          $endgroup$




















            1












            $begingroup$

            I think your functional approach is very nice, and scores high points for readability. As long as the recursion wasn't causing performance issues, that's how I'd approach it.



            However, it's not very efficient, and as vnp points out, listing permutations is really just a matter of counting from 1 to "the number of combinations" in a mixed base numbering system.



            mixed base counting



            These are easy implement, and it's worth going through the exercise, because assuming you have a utility that does the mixed base counting for you, the solution to the original problem will be both straightforward and efficient:



            function mixedBaseCounter(bases) 
            let cnt = 0
            let maxCnt = bases.length ? [...bases].reduce((m, x) => m * x, 1) : 0
            let digits = bases.map(() => 0)

            const increment = (i = 0) =>
            digits[i] = (digits[i] + 1) % bases[i]
            if (digits[i] == 0) increment(i + 1)


            return
            [Symbol.iterator]: function* ()
            while (cnt++ < maxCnt)
            yield digits.join('')
            increment()






            This uses ECMA script's iterable interface. Note the above implementation has the least significant bit on the left (easily changed, if you need to).



            Let's verify it counts correctly in binary:



            [...mixedBaseCounter([2, 2, 2])]
            // [ '000', '100', '010', '110', '001', '101', '011', '111' ]


            And that it handles mixed bases:



            console.log([...mixedBaseCounter([2, 3])])
            // [ '00', '10', '01', '11', '02', '12' ]


            Try it online!



            applying it to the problem



            Now the solutions becomes:



            function letterCombinations(digits) 

            const strDigits =
            '2': 'abc',
            '3': 'def',
            '4': 'ghi',
            '5': 'jkl',
            '6': 'mno',
            '7': 'pqrs',
            '8': 'tuv',
            '9': 'wxyz',


            const letterOptions = [...digits].map(x => strDigits[x])
            const bases = [...letterOptions].map(x => x.length)
            const masks = mixedBaseCounter(bases)

            return [...masks].map(m =>
            [...m].map((x, i) => letterOptions[i][x]).join('')
            )



            where each "mask" (or number, within the mixed base numbering system) chooses one combination.



            Note also we no longer need to treat the empty string as a special case.



            Try it online!






            share|improve this answer









            $endgroup$













              Your Answer






              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "196"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













              draft saved

              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f221976%2ffind-all-letter-combinations-of-a-phone-number%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              4












              $begingroup$


              whenever you encounter a task where you have to combine or permute things, then backtracking is a possible approach.




              True. It is not necessarily the best though (in fact it is rarely the best).



              In this particular case, the problem naturally maps to finding the next combination. In turn, it is no more than an increment of a number in some fancy numbering system. In your example, the minimal possible string is ad. Subsequent increments yield ae, then af, then ('f' + 1 is d and a carry bit does carry) bd, etc.



              Consider implementing the increment/next method directly. The space complexity will definitely benefit; and it is trivial to convert into a generator. The time complexity is likely to also benefit, depending on the use case.



              PS: thank you for posting your train of thoughts.






              share|improve this answer









              $endgroup$

















                4












                $begingroup$


                whenever you encounter a task where you have to combine or permute things, then backtracking is a possible approach.




                True. It is not necessarily the best though (in fact it is rarely the best).



                In this particular case, the problem naturally maps to finding the next combination. In turn, it is no more than an increment of a number in some fancy numbering system. In your example, the minimal possible string is ad. Subsequent increments yield ae, then af, then ('f' + 1 is d and a carry bit does carry) bd, etc.



                Consider implementing the increment/next method directly. The space complexity will definitely benefit; and it is trivial to convert into a generator. The time complexity is likely to also benefit, depending on the use case.



                PS: thank you for posting your train of thoughts.






                share|improve this answer









                $endgroup$















                  4












                  4








                  4





                  $begingroup$


                  whenever you encounter a task where you have to combine or permute things, then backtracking is a possible approach.




                  True. It is not necessarily the best though (in fact it is rarely the best).



                  In this particular case, the problem naturally maps to finding the next combination. In turn, it is no more than an increment of a number in some fancy numbering system. In your example, the minimal possible string is ad. Subsequent increments yield ae, then af, then ('f' + 1 is d and a carry bit does carry) bd, etc.



                  Consider implementing the increment/next method directly. The space complexity will definitely benefit; and it is trivial to convert into a generator. The time complexity is likely to also benefit, depending on the use case.



                  PS: thank you for posting your train of thoughts.






                  share|improve this answer









                  $endgroup$




                  whenever you encounter a task where you have to combine or permute things, then backtracking is a possible approach.




                  True. It is not necessarily the best though (in fact it is rarely the best).



                  In this particular case, the problem naturally maps to finding the next combination. In turn, it is no more than an increment of a number in some fancy numbering system. In your example, the minimal possible string is ad. Subsequent increments yield ae, then af, then ('f' + 1 is d and a carry bit does carry) bd, etc.



                  Consider implementing the increment/next method directly. The space complexity will definitely benefit; and it is trivial to convert into a generator. The time complexity is likely to also benefit, depending on the use case.



                  PS: thank you for posting your train of thoughts.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 5 hours ago









                  vnpvnp

                  41.5k234106




                  41.5k234106























                      1












                      $begingroup$

                      I think your functional approach is very nice, and scores high points for readability. As long as the recursion wasn't causing performance issues, that's how I'd approach it.



                      However, it's not very efficient, and as vnp points out, listing permutations is really just a matter of counting from 1 to "the number of combinations" in a mixed base numbering system.



                      mixed base counting



                      These are easy implement, and it's worth going through the exercise, because assuming you have a utility that does the mixed base counting for you, the solution to the original problem will be both straightforward and efficient:



                      function mixedBaseCounter(bases) 
                      let cnt = 0
                      let maxCnt = bases.length ? [...bases].reduce((m, x) => m * x, 1) : 0
                      let digits = bases.map(() => 0)

                      const increment = (i = 0) =>
                      digits[i] = (digits[i] + 1) % bases[i]
                      if (digits[i] == 0) increment(i + 1)


                      return
                      [Symbol.iterator]: function* ()
                      while (cnt++ < maxCnt)
                      yield digits.join('')
                      increment()






                      This uses ECMA script's iterable interface. Note the above implementation has the least significant bit on the left (easily changed, if you need to).



                      Let's verify it counts correctly in binary:



                      [...mixedBaseCounter([2, 2, 2])]
                      // [ '000', '100', '010', '110', '001', '101', '011', '111' ]


                      And that it handles mixed bases:



                      console.log([...mixedBaseCounter([2, 3])])
                      // [ '00', '10', '01', '11', '02', '12' ]


                      Try it online!



                      applying it to the problem



                      Now the solutions becomes:



                      function letterCombinations(digits) 

                      const strDigits =
                      '2': 'abc',
                      '3': 'def',
                      '4': 'ghi',
                      '5': 'jkl',
                      '6': 'mno',
                      '7': 'pqrs',
                      '8': 'tuv',
                      '9': 'wxyz',


                      const letterOptions = [...digits].map(x => strDigits[x])
                      const bases = [...letterOptions].map(x => x.length)
                      const masks = mixedBaseCounter(bases)

                      return [...masks].map(m =>
                      [...m].map((x, i) => letterOptions[i][x]).join('')
                      )



                      where each "mask" (or number, within the mixed base numbering system) chooses one combination.



                      Note also we no longer need to treat the empty string as a special case.



                      Try it online!






                      share|improve this answer









                      $endgroup$

















                        1












                        $begingroup$

                        I think your functional approach is very nice, and scores high points for readability. As long as the recursion wasn't causing performance issues, that's how I'd approach it.



                        However, it's not very efficient, and as vnp points out, listing permutations is really just a matter of counting from 1 to "the number of combinations" in a mixed base numbering system.



                        mixed base counting



                        These are easy implement, and it's worth going through the exercise, because assuming you have a utility that does the mixed base counting for you, the solution to the original problem will be both straightforward and efficient:



                        function mixedBaseCounter(bases) 
                        let cnt = 0
                        let maxCnt = bases.length ? [...bases].reduce((m, x) => m * x, 1) : 0
                        let digits = bases.map(() => 0)

                        const increment = (i = 0) =>
                        digits[i] = (digits[i] + 1) % bases[i]
                        if (digits[i] == 0) increment(i + 1)


                        return
                        [Symbol.iterator]: function* ()
                        while (cnt++ < maxCnt)
                        yield digits.join('')
                        increment()






                        This uses ECMA script's iterable interface. Note the above implementation has the least significant bit on the left (easily changed, if you need to).



                        Let's verify it counts correctly in binary:



                        [...mixedBaseCounter([2, 2, 2])]
                        // [ '000', '100', '010', '110', '001', '101', '011', '111' ]


                        And that it handles mixed bases:



                        console.log([...mixedBaseCounter([2, 3])])
                        // [ '00', '10', '01', '11', '02', '12' ]


                        Try it online!



                        applying it to the problem



                        Now the solutions becomes:



                        function letterCombinations(digits) 

                        const strDigits =
                        '2': 'abc',
                        '3': 'def',
                        '4': 'ghi',
                        '5': 'jkl',
                        '6': 'mno',
                        '7': 'pqrs',
                        '8': 'tuv',
                        '9': 'wxyz',


                        const letterOptions = [...digits].map(x => strDigits[x])
                        const bases = [...letterOptions].map(x => x.length)
                        const masks = mixedBaseCounter(bases)

                        return [...masks].map(m =>
                        [...m].map((x, i) => letterOptions[i][x]).join('')
                        )



                        where each "mask" (or number, within the mixed base numbering system) chooses one combination.



                        Note also we no longer need to treat the empty string as a special case.



                        Try it online!






                        share|improve this answer









                        $endgroup$















                          1












                          1








                          1





                          $begingroup$

                          I think your functional approach is very nice, and scores high points for readability. As long as the recursion wasn't causing performance issues, that's how I'd approach it.



                          However, it's not very efficient, and as vnp points out, listing permutations is really just a matter of counting from 1 to "the number of combinations" in a mixed base numbering system.



                          mixed base counting



                          These are easy implement, and it's worth going through the exercise, because assuming you have a utility that does the mixed base counting for you, the solution to the original problem will be both straightforward and efficient:



                          function mixedBaseCounter(bases) 
                          let cnt = 0
                          let maxCnt = bases.length ? [...bases].reduce((m, x) => m * x, 1) : 0
                          let digits = bases.map(() => 0)

                          const increment = (i = 0) =>
                          digits[i] = (digits[i] + 1) % bases[i]
                          if (digits[i] == 0) increment(i + 1)


                          return
                          [Symbol.iterator]: function* ()
                          while (cnt++ < maxCnt)
                          yield digits.join('')
                          increment()






                          This uses ECMA script's iterable interface. Note the above implementation has the least significant bit on the left (easily changed, if you need to).



                          Let's verify it counts correctly in binary:



                          [...mixedBaseCounter([2, 2, 2])]
                          // [ '000', '100', '010', '110', '001', '101', '011', '111' ]


                          And that it handles mixed bases:



                          console.log([...mixedBaseCounter([2, 3])])
                          // [ '00', '10', '01', '11', '02', '12' ]


                          Try it online!



                          applying it to the problem



                          Now the solutions becomes:



                          function letterCombinations(digits) 

                          const strDigits =
                          '2': 'abc',
                          '3': 'def',
                          '4': 'ghi',
                          '5': 'jkl',
                          '6': 'mno',
                          '7': 'pqrs',
                          '8': 'tuv',
                          '9': 'wxyz',


                          const letterOptions = [...digits].map(x => strDigits[x])
                          const bases = [...letterOptions].map(x => x.length)
                          const masks = mixedBaseCounter(bases)

                          return [...masks].map(m =>
                          [...m].map((x, i) => letterOptions[i][x]).join('')
                          )



                          where each "mask" (or number, within the mixed base numbering system) chooses one combination.



                          Note also we no longer need to treat the empty string as a special case.



                          Try it online!






                          share|improve this answer









                          $endgroup$



                          I think your functional approach is very nice, and scores high points for readability. As long as the recursion wasn't causing performance issues, that's how I'd approach it.



                          However, it's not very efficient, and as vnp points out, listing permutations is really just a matter of counting from 1 to "the number of combinations" in a mixed base numbering system.



                          mixed base counting



                          These are easy implement, and it's worth going through the exercise, because assuming you have a utility that does the mixed base counting for you, the solution to the original problem will be both straightforward and efficient:



                          function mixedBaseCounter(bases) 
                          let cnt = 0
                          let maxCnt = bases.length ? [...bases].reduce((m, x) => m * x, 1) : 0
                          let digits = bases.map(() => 0)

                          const increment = (i = 0) =>
                          digits[i] = (digits[i] + 1) % bases[i]
                          if (digits[i] == 0) increment(i + 1)


                          return
                          [Symbol.iterator]: function* ()
                          while (cnt++ < maxCnt)
                          yield digits.join('')
                          increment()






                          This uses ECMA script's iterable interface. Note the above implementation has the least significant bit on the left (easily changed, if you need to).



                          Let's verify it counts correctly in binary:



                          [...mixedBaseCounter([2, 2, 2])]
                          // [ '000', '100', '010', '110', '001', '101', '011', '111' ]


                          And that it handles mixed bases:



                          console.log([...mixedBaseCounter([2, 3])])
                          // [ '00', '10', '01', '11', '02', '12' ]


                          Try it online!



                          applying it to the problem



                          Now the solutions becomes:



                          function letterCombinations(digits) 

                          const strDigits =
                          '2': 'abc',
                          '3': 'def',
                          '4': 'ghi',
                          '5': 'jkl',
                          '6': 'mno',
                          '7': 'pqrs',
                          '8': 'tuv',
                          '9': 'wxyz',


                          const letterOptions = [...digits].map(x => strDigits[x])
                          const bases = [...letterOptions].map(x => x.length)
                          const masks = mixedBaseCounter(bases)

                          return [...masks].map(m =>
                          [...m].map((x, i) => letterOptions[i][x]).join('')
                          )



                          where each "mask" (or number, within the mixed base numbering system) chooses one combination.



                          Note also we no longer need to treat the empty string as a special case.



                          Try it online!







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered 23 mins ago









                          JonahJonah

                          3,661719




                          3,661719



























                              draft saved

                              draft discarded
















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid


                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.

                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f221976%2ffind-all-letter-combinations-of-a-phone-number%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                              Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                              Tom Holland Mục lục Đầu đời và giáo dục | Sự nghiệp | Cuộc sống cá nhân | Phim tham gia | Giải thưởng và đề cử | Chú thích | Liên kết ngoài | Trình đơn chuyển hướngProfile“Person Details for Thomas Stanley Holland, "England and Wales Birth Registration Index, 1837-2008" — FamilySearch.org”"Meet Tom Holland... the 16-year-old star of The Impossible""Schoolboy actor Tom Holland finds himself in Oscar contention for role in tsunami drama"“Naomi Watts on the Prince William and Harry's reaction to her film about the late Princess Diana”lưu trữ"Holland and Pflueger Are West End's Two New 'Billy Elliots'""I'm so envious of my son, the movie star! British writer Dominic Holland's spent 20 years trying to crack Hollywood - but he's been beaten to it by a very unlikely rival"“Richard and Margaret Povey of Jersey, Channel Islands, UK: Information about Thomas Stanley Holland”"Tom Holland to play Billy Elliot""New Billy Elliot leaving the garage"Billy Elliot the Musical - Tom Holland - Billy"A Tale of four Billys: Tom Holland""The Feel Good Factor""Thames Christian College schoolboys join Myleene Klass for The Feelgood Factor""Government launches £600,000 arts bursaries pilot""BILLY's Chapman, Holland, Gardner & Jackson-Keen Visit Prime Minister""Elton John 'blown away' by Billy Elliot fifth birthday" (video with John's interview and fragments of Holland's performance)"First News interviews Arrietty's Tom Holland"“33rd Critics' Circle Film Awards winners”“National Board of Review Current Awards”Bản gốc"Ron Howard Whaling Tale 'In The Heart Of The Sea' Casts Tom Holland"“'Spider-Man' Finds Tom Holland to Star as New Web-Slinger”lưu trữ“Captain America: Civil War (2016)”“Film Review: ‘Captain America: Civil War’”lưu trữ“‘Captain America: Civil War’ review: Choose your own avenger”lưu trữ“The Lost City of Z reviews”“Sony Pictures and Marvel Studios Find Their 'Spider-Man' Star and Director”“‘Mary Magdalene’, ‘Current War’ & ‘Wind River’ Get 2017 Release Dates From Weinstein”“Lionsgate Unleashing Daisy Ridley & Tom Holland Starrer ‘Chaos Walking’ In Cannes”“PTA's 'Master' Leads Chicago Film Critics Nominations, UPDATED: Houston and Indiana Critics Nominations”“Nominaciones Goya 2013 Telecinco Cinema – ENG”“Jameson Empire Film Awards: Martin Freeman wins best actor for performance in The Hobbit”“34th Annual Young Artist Awards”Bản gốc“Teen Choice Awards 2016—Captain America: Civil War Leads Second Wave of Nominations”“BAFTA Film Award Nominations: ‘La La Land’ Leads Race”“Saturn Awards Nominations 2017: 'Rogue One,' 'Walking Dead' Lead”Tom HollandTom HollandTom HollandTom Hollandmedia.gettyimages.comWorldCat Identities300279794no20130442900000 0004 0355 42791085670554170004732cb16706349t(data)XX5557367