[英]Return String as Sorted Blocks - Codewars Challenge - JavaScript
我一直在努力解決這個代碼戰挑戰。 這個想法是返回字符串,根據其層次結構重新排列,或根據重復字符分成塊。
您將收到一個由小寫字母、大寫字母和數字組成的字符串作為輸入。 您的任務是將此字符串作為由破折號(“-”)分隔的塊返回。 塊的元素應按照下面列出的層次結構進行排序,並且每個塊不能包含同一字符的多個實例。
層次結構是:
小寫字母 (a - z),按字母順序 大寫字母 (A - Z),按字母順序數字 (0 - 9),按升序 示例
"21AxBz" -> "xzAB12"
- 由於輸入不包含重復字符,您只需要 1 個塊
"abacad" -> "abcd-aa"
- 字符“a”重復 3 次,因此需要 3 個塊
"" -> ""
- 空輸入應該導致空輸出
我嘗試過的實際上適用於給定的測試用例:
describe("Sample tests", () => {
it("Tests", () => {
assert.equal(blocks("21AxBz"), "xzAB12");
assert.equal(blocks("abacad"), "abcd-a-a");
assert.equal(blocks(""), "");
});
});
但是當有任何重復字符時失敗,除了在測試用例中:
function repeatingChar(str){ const result = []; const strArr = str.toLowerCase().split("").sort().join("").match(/(.)\\1+/g); if (strArr != null) { strArr.forEach((elem) => { result.push(elem[0]); }); } return result; } function blocks(s) { if (s.length === 0) { return ''; } //if string does not contain repeating characters if (!/(.).*\\1/.test(s) === true) { let lower = s.match(/[az]/g).join(''); let upper = s.match(/[AZ]/g).join(''); let numbers = s.match(/[\\d]/g).sort().join(''); return lower + upper + numbers; } //if string contains repeating characters if (!/(.).*\\1/.test(s) === false) { let repeatChar = (repeatingChar(s)[0]); let repeatRegex = new RegExp(repeatingChar(s)[0]); let repeatCount = s.match(/[repeatRegex]/gi).length; let nonAChars = s.match(/[^a]/gi).join(''); function getPosition(string, subString, index) { return s.split(repeatChar, index).join(repeatChar).length; } let index = getPosition(s, repeatChar, 2); // console.log('indexxxxx', index); return s.slice(0, index) + nonAChars.slice(1) + ('-' + repeatChar).repeat(repeatCount - 1); } } console.log(blocks("abacad"));
實際上,我不確定它有什么問題,因為我不知道如何在 Codewars 上解鎖任何其他測試。
您可以看到我正在嘗試做的是找到重復字符,獲取所有不是重復字符的字符,然后將字符串從起始點切片直到重復字符的第 2 個實例,然后添加末尾剩余的重復字符,以破折號分隔。
關於如何做到這一點的任何其他建議?
我能看到的第一個明顯錯誤是let repeatCount = s.match(/[repeatRegex]/gi).length;
. 你真正想做的是:
let repeatRegex = new RegExp(repeatingChar(s)[0], 'g');
let repeatCount = s.match(repeatRegex).length;
接下來是您只查看重復字符中的一個,而不是全部,因此您不會得到正確形式的塊,因此您需要遍歷它們。
let repeatedChars = repeatingChar(s);
for(let c of repeatedChars)
{
//figure out blocks
}
當您構建塊時,您已決定專注於不是“a”的所有內容。 我猜這不是您最初編寫的內容,而是一些調試代碼,用於處理該示例輸入。
如果我正確理解你的願望,你想把所有不重復的字符放在一起,然后把第一個重復字符的第一個實例放在前面,然后把重復字符的剩余實例塞進前面返回,以-
分隔。
這里的問題是第一個重復的字符可能不是結果中應該排在第一位的字符。 從本質上講,你很幸運與重復的字符是a
。
修復您的代碼,我將創建一個數組並單獨構建塊,然后在最后將它們連接在一起。
let repeatedChars = repeatingChar(s);
let blocks = []
for(let c of repeatedChars)
{
let repeatRegex = new RegExp(c, 'g');
let repeatCount = s.match(repeatRegex).length;
for(let i = 1; i <= repeatCount; i++)
{
if(blocks.length < i)
{
let newBlock = [c];
blocks.push(newBlock);
}
else
{
block[i - 1].push(c);
}
}
}
let tailBlocks = blocks.map(block => block.join('')).join('-');
但是,這給我留下了一個問題,即如何以正確的順序構建包含非重復字符的最終字符串。
所以,首先,讓我們制作初始字符串。 為此,我們需要一個自定義排序函數(抱歉,它太冗長了。如果我們可以使用常規的 ASCII 排序就好了):
function lowerUpperNumber(a, b)
{
if(a.match(/[a-z]/) && b.match(/[A-Z0-9]/))
{
return -1;
}
else if(a.match(/[A-Z]/) && (b.match(/[0-9]/) || b.match(/[a-z]/)))
{
if(b.match(/[0-9]/))
{
return -1;
}
else if(b.match(/[a-z]/))
{
return 1;
}
}
else if(a.match(/[0-9]/) && b.match(/[a-zA-Z]/))
{
return 1;
}
else if(a > b)
{
return 1;
}
else if(a < b)
{
return -1;
}
return 0;
}
然后創建最終輸出的頭部:
let firstBlock = [...(new Set(s))].sort(lowerUpperNumber);
Set
創建一組獨特的元素,即沒有重復。
因為我們已經創建了頭字符串,所以在創建重復字符塊時,我們需要比上面循環給我們的少一個,所以我們將使用s.match(repeatRegex).length-1
。
我希望將復雜的位短路並在沒有重復字符時快速返回,但為了簡潔起見,我將刪除該位,而且我不想處理未定義的值(例如嘗試'123'
作為您的輸入)。
讓我們把它放在一起:
function lowerUpperNumber(a, b) { if(a.match(/[az]/) && b.match(/[A-Z0-9]/)) { return -1; } else if(a.match(/[AZ]/) && (b.match(/[0-9]/) || b.match(/[az]/))) { if(b.match(/[0-9]/)) { return -1; } else if(b.match(/[az]/)) { return 1; } } else if(a.match(/[0-9]/) && b.match(/[a-zA-Z]/)) { return 1; } else if(a > b) { return 1; } else if(a < b) { return -1; } return 0; } function makeBlocks(s) { if (s.length === 0) { return ''; } let firstBlock = [...(new Set(s))].sort(lowerUpperNumber); let firstString = firstBlock.join(''); let blocks = []; for(let c of firstString) { let repeatRegex = new RegExp(c, 'g'); let repeatCount = s.match(repeatRegex).length - 1; for(let i = 1; i <= repeatCount; i++) { if(blocks.length < i) { let newBlock = [c]; blocks.push(newBlock); } else { blocks[i - 1].push(c); } } } blocks.unshift(firstBlock); return blocks.map(block => block.join('')).join('-'); } console.log(makeBlocks('21AxBz')); console.log(makeBlocks('abacad')); console.log(makeBlocks('Any9Old4String22With7Numbers')); console.log(makeBlocks(''));
你會看到我沒有費心去生成重復的字符,因為我可以跳過那些不重復的字符。
對於funzies,這是我解決問題的方法:
const isLower = new RegExp('[az]'); const isUpper = new RegExp('[AZ]'); const isDigit = new RegExp('[0-9]'); const isDigitOrUpper = new RegExp('[0-9A-Z]'); const isDigitOrLower = new RegExp('[0-9a-z]'); const isLowerOrUpper = new RegExp('[a-zA-Z]'); function lowerUpperNumber(a, b) { if(isLower.test(a) && isDigitOrUpper.test(b)) { return -1; } else if(isUpper.test(a) && isDigitOrLower.test(b)) { if(isDigit.test(b)) { return -1; } else if(isLower.test(b)) { return 1; } } else if(isDigit.test(a) && isLowerOrUpper.test(b)) { return 1; } else if(a > b) { return 1; } else if(a < b) { return -1; } return 0; } function makeBlocks(input) { let sortedInput = input.split(''); sortedInput.sort(lowerUpperNumber); let output = ''; let blocks = []; for(let c of sortedInput) { let inserted = false; for(let block of blocks) { if(block.indexOf(c) === -1) { inserted = true; block.push(c); break; } } if(!inserted) { blocks.push([c]); } } output = blocks.map(block => block.join('')).join('-'); return output; } console.log(makeBlocks('21AxBz')); console.log(makeBlocks('abacad')); console.log(makeBlocks('Any9Old4String22With7Numbers')); console.log(makeBlocks(''));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.