我读了一些编程脑筋笑话,看到了一个T9翻译器对代码疯狂的戏弄,并想在node.js中实现它。
从电话号码数字中打印所有可能的单词。这个问题是由微软、谷歌、facebook、亚马逊等公司提出的。让我们看看输入/输出示例来理解这个问题。例如,如果输入编号为234,可以形成的单词为(字母顺序):adg cdh aeg aeh aei afg afi afi bdg bdh bdi求beh be bfg bfh bfi cdg cdh cdi cdi cfg cfg cfh cfi cfi bfi
我担心太多的迭代和可读性。我最初只在递归函数中进行增量,但随后需要对结果数组执行一个.reverse(),我认为这样做更好,只需在转换本身中通过递减来处理。我也想知道我是否在以正确的方式进行我的测试。
/*jslint node:true, es5:true*/
/*
* Based on problem presented by:
* http://www.crazyforcode.com/print-words-phone-digits/
*/
"use strict";
/**
* T9 module
* @module t9
*/
var t9 = [
[" "], // 0
[""], // 1
["a", "b", "c"], // 2
["d", "e", "f"], // 3
["g", "h", "i"], // 4
["j", "k", "l"], // 5
["m", "n", "o"], // 6
["p", "q", "r", "s"], // 7
["t", "u", "v"], // 8
["w", "x", "y", "z"] // 9
];
function rec(bundles, bundleIdx, letterIdx, str, arr) {
// Add the new letter
var concatedStr = str + bundles[bundleIdx][letterIdx];
// Decrement letter
if (letterIdx > 0) {
rec(bundles, bundleIdx, letterIdx - 1, str, arr);
}
// Increment bundle
if (bundleIdx < bundles.length - 1) {
rec(bundles, bundleIdx + 1, bundles[bundleIdx + 1].length - 1, concatedStr, arr);
}
// Not a complete word
if (concatedStr.length < bundles.length) {
return;
}
// Push word
arr.push(concatedStr);
}
/**
* Find all the words that could be made with given number using T9 translation
* @function translate
* @param {String} numbers The number to translate with t9
* @returns {String[]} Possible words that could be made
* @throws Will throw if a non-number string is provided
*/
function translate(numbers) {
var possibleWords,
charArrs;
if (!/^[0-9]+$/.test(numbers)) {
throw new Error("Must provide a number string");
}
possibleWords = [];
charArrs = numbers
.split("")
.map(function (digit) {
return t9[parseInt(digit, 10)];
});
// Start recursive func
rec(charArrs, 0, charArrs[0].length - 1, "", possibleWords);
return possibleWords;
}
module.exports = {
translate: translate
};/*jslint node:true, es5:true*/
"use strict";
var assert = require("assert"),
t9 = require("../src/t9");
// Throw errors properly
assert.throws(function () {
t9.translate("hello");
}, Error, "Expected an error");
// Translate 3 letter numbers correctly
var expected234 = ["adg", "adh", "adi", "aeg", "aeh", "aei", "afg", "afh", "afi", "bdg", "bdh", "bdi", "beg", "beh", "bei", "bfg", "bfh", "bfi", "cdg", "cdh", "cdi", "ceg", "ceh", "cei", "cfg", "cfh", "cfi"],
actual234 = t9.translate("234");
assert.deepEqual(expected234, actual234, "Expected 3 numbers to translate");
// Translates 3 and 4 letter numbers correctly
var expected78 = ["pt", "pu", "pv", "qt", "qu", "qv", "rt", "ru", "rv", "st", "su", "sv"],
actual78 = t9.translate("78");
assert.deepEqual(expected78, actual78, "Expected 3 and 4 numbers to translate");
// Translates with a space
var expected506 = ["j m", "j n", "j o", "k m", "k n", "k o", "l m", "l n", "l o"],
actual506 = t9.translate("506");
assert.deepEqual(expected506, actual506, "Expected spaces to work");
// Translate complex message
var expected2067 = ["a mp", "a mq", "a mr", "a ms", "a np", "a nq", "a nr", "a ns", "a op", "a oq", "a or", "a os", "b mp", "b mq", "b mr", "b ms", "b np", "b nq", "b nr", "b ns", "b op", "b oq", "b or", "b os", "c mp", "c mq", "c mr", "c ms", "c np", "c nq", "c nr", "c ns", "c op", "c oq", "c or", "c os", ],
actual2067 = t9.translate("2067");
assert.deepEqual(expected2067, actual2067, "Complex translate to work");/*jslint node:true, es5:true*/
"use strict";
var t9 = require("./src/t9");
function handleInput(toTranslate) {
console.log("Possible words:");
t9.translate(toTranslate).forEach(function (possibleWord) {
console.log(possibleWord);
});
}
if (process.argv.length > 2) {
handleInput(process.argv[2]);
} else {
var rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("What numbers? ", function (answer) {
rl.close();
handleInput(answer);
});
}发布于 2017-05-16 04:55:18
这看起来不错,但我认为您不必要地引入了第二个函数,并且使用了比您需要的更多的参数,从而使基本递归变得有点复杂。
下面完成了同样的事情(注意,其中将近一半是与您的输入验证类似的输入验证,因此算法的实质是六行行):
function t9Words(digits, ret = []) {
if (typeof digits === 'string') {
digits = digits.split('').map(x => {
if (!/\d/.test(x)) throw new Error('Input must be digits')
return parseInt(x)
})
}
if (!digits.length) return ret.sort() // recursion bottom case
if (!ret.length) return t9Words(digits.slice(1), t9[digits[0]]) // top case
const nextRet = t9[digits[0]].reduce((m, x) =>
m.concat(ret.map(word => word.concat(x)))
, [])
return t9Words(digits.slice(1), nextRet)
}https://codereview.stackexchange.com/questions/163429
复制相似问题