I am taking the challenges from code-wars and I am looking at a solution and I don't understand it. Can somebody explain what s is doing as well as o?
function duplicateEncode(word) {
word = word.toLowerCase();
var c = '', s = '', o = '';
for (i = 0; i < word.length; i++) {
s = word.slice(i + 1);
o = s + word.slice(0, i);
c += (o.indexOf(word[i]) > -1) ? ')' : '(';
}
return c;
}
From String.prototype.slice MDN documentation:
beginIndex
The zero-based index at which to begin extraction. If
negative, it is treated as strLength + (beginIndex) where strLength is
the length of the string (for example, if beginIndex is -3 it is
treated as strLength - 3). If beginIndex is greater than or equal to
the length of the string, slice() returns an empty string.
endIndex
Optional. The zero-based index before which to end extraction. The
character at this index will not be included. If endIndex is omitted,
slice() extracts to the end of the string. If negative, it is treated
as strLength + endIndex where strLength is the length of the string
(for example, if endIndex is -3 it is treated as strLength - 3).
s = word.slice(i + 1);
o = s + word.slice(0, i);
these two lines get what's after the current character and what's before it and concatenate these two pieces. In other words, they build a string equal to the source string with the current char omitted. For example, if word is abcde and i=2, then o will be de + ab = deab. Of course, they could have simply written
o = word.slice(0, i) + word.slice(i + 1)
with the same effect.
As a side note, this algorithm appears quite inefficient as it builds word.length temporary strings just to check the uniqueness. A more idiomatic approach would be to use (last)indexOf along the lines of
function duplicateEncode(word) {
let w = [...word.toLowerCase()];
return w
.map(c => w.indexOf(c) === w.lastIndexOf(c) ? '(' : ')')
.join('')
}
s will contain all the characters in word after the character at the current iteration
o will contain all the characters in word except the one at the current iteration (s + [all the characters in word from start till the one at the current iteration]).
This means that the (o.indexOf(word[i]) > -1 ) expression will only be true if the character at the current iteration has a duplicate.
Related
I want to know how can I print the number of characters of a string that does not change its position after reversal of that string in JavaScript.
Is there any way?
data stream - alphxxdida . After reverse - adidaxxhpla. so here x and a doesn't changed it position. How can I do this ?
Input - alphxxdida
Output-4
A character doesn't change upon reverse if the character in the "mirror image" position is the same character. The "mirror image" position of a character n positions from the start of the string is the character n positions from the end of the string.
let mirroredChars = str => {
let result = [];
let halfLen = Math.ceil(str.length / 2);
let lastIndex = str.length - 1;
for (let i = 0; i < halfLen; i++) {
if (str[i] === str[lastIndex - i]) result.push(str[i]);
}
return result;
};
console.log(mirroredChars('alphxxdida'));
The count is actually slightly unintuitive. We can't simply take 2 * mirroredChars(...).length, since that would imply the number of mirrored characters is always even (and odd counts can occur, in any odd-length input string, since the middle character can always be considered mirrored).
The count will be:
let countMirroredChars = str => {
let numMirrored = mirroredChars(str).length;
return (str.length % 2) // "Is the input string of odd length?"
? (numMirrored * 2 - 1)
: (numMirrored * 2);
};
We can use a bitwise trick to shorten this code. Either of the following work (and the second should deliver better performance, but looks a bit mystical):
let countMirroredChars = str => mirroredChars(str).length * 2 - str.length % 2;
let countMirroredChars = str => mirroredChars(str).length * 2 - str.length & 1;
You can filter over the characters of the string and compare with the character at the corresponding index in the reversed string. The length of the filtered array will be the number of characters that remained the same.
var str = "alphxxdida";
var reversed = [...str].reverse().join('');
const same = [...str].filter((char,i)=>char===reversed[i]);
console.log(same.length);
Of course, you don't actually need the reversed string to perform the filter, as you can calculate the index of the mirrored character.
var str = "alphxxdida";
var same = [...str].filter((char,i)=>char===str[str.length - i - 1]);
console.log(same.length);
Here is with reduce. Traverse till half length of string and compare the chars from both ends of string and count.
Update: As #Gershom pointed out, Fixed to work for odd length of string.
const getCount = (str) =>
[...str.slice(0, str.length / 2)].reduce(
(acc, char, i) => acc + (char === str[str.length - 1 - i] ? 2 : 0),
str.length % 2
);
var str = "alphxxdida";
var str2 = "alphxdida";
console.log(str, getCount(str));
console.log(str2, getCount(str2));
I am trying to solve this particular algorithm question:
You are given a license key represented as a string S which consists only alphanumeric character and dashes. The string is separated into N+1 groups by N dashes.
Given a number K, we would want to reformat the strings such that each group contains exactly K characters, except for the first group which could be shorter than K, but still must contain at least one character. Furthermore, there must be a dash inserted between two groups and all lowercase letters should be converted to uppercase.
Given a non-empty string S and a number K, format the string according to the rules described above.
Example 1:
Input: S = "5F3Z-2e-9-w", K = 4
Output: "5F3Z-2E9W"
Explanation: The string S has been split into two parts, each part has 4 characters.
Note that the two extra dashes are not needed and can be removed.
Example 2:
Input: S = "2-5g-3-J", K = 2
Output: "2-5G-3J"
Explanation: The string S has been split into three parts, each part has 2 characters except the first part as it could be shorter as mentioned above.
Note:
The length of string S will not exceed 12,000, and K is a positive integer.
String S consists only of alphanumerical characters (a-z and/or A-Z and/or 0-9) and dashes(-).
String S is non-empty.
I have written the following code:
const licenseKeyFormatting = (S, K) => {
//convert to array, remove special characters, and capitalize
let s = [...S.replace(/\W/g, '').toUpperCase()]
let pos = 1
//from end of array add '-' for every K
for (let i = s.length - 1; i > 0; i--) {
if (pos === K) {
s.splice(i, 0, '-')
pos = 1
i-- //re-index bc adding to the array
}
pos++
}
return s
}
console.log(licenseKeyFormatting("5F3Z-2e-9-w", 4)) //5F3Z-2E9W
console.log(licenseKeyFormatting("2-5g-3-J", 2)) //2-5G-3J
console.log(licenseKeyFormatting("a-a-a-a-", 1)) // this test case fails should be A-A-A-A, I am getting AAA-A
I am pretty sure the flaw in my logic is due to the re-index, but I can't figure out how to address it.
You should not alter the index. Using splice to insert an element pushes the other elements back, however since you iterate from back to front that doesn't matter. You've already handled the shifted elements.
Another issue is setting pos = 1 in the loop. This is directly followed by pos++. So when pos reaches K the value of pos will be reset to 2 at the end of the loop. Either set pos = 0 (in the loop) so it ends on 1 or move pos++ into the else section.
const licenseKeyFormatting = (S, K) => {
//convert to array, remove special characters, and capitalize
let s = [...S.replace(/\W/g, '').toUpperCase()]
let pos = 1
//from end of array add '-' for every K
for (let i = s.length - 1; i > 0; i--) {
if (pos === K) {
s.splice(i, 0, '-')
pos = 0
}
pos++
}
return s.join("") // <- added join for cleaner console output
}
console.log(licenseKeyFormatting("5F3Z-2e-9-w", 4)) //5F3Z-2E9W
console.log(licenseKeyFormatting("2-5g-3-J", 2)) //2-5G-3J
console.log(licenseKeyFormatting("a-a-a-a-", 1)) // this test case fails should be A-A-A-A, I am getting AAA-A
my way....
function licenseKeyFormatting( S, K )
{
let arr = [...S.replace(/\W/g, '').toUpperCase()]
, p = 0
;
for (let i=arr.length;i--;)
{
p = ++p % K // p = (p+1) % K
if (!p&&i) arr.splice(i,0,'-') // if p===0 and i>0
}
return arr.join('')
}
console.log(licenseKeyFormatting("5F3Z-2e-9-w", 4)) // 5F3Z-2E9W
console.log(licenseKeyFormatting("2-5g-3-J", 2)) // 2-5G-3J
console.log(licenseKeyFormatting("a-a-a-a-", 1)) // A-A-A-A
OR: (more simple)
function licenseKeyFormatting( S, K )
{
let arr = [...S.replace(/\W/g, '').toUpperCase()];
for (let p=arr.length-K;p>0;p-=K) arr.splice(p,0,'-');
return arr.join('');
}
console.log( licenseKeyFormatting("5F3Z-2e-9-w", 4)) // 5F3Z-2E9W
console.log( licenseKeyFormatting("2-5g-3-J", 2)) // 2-5G-3J
console.log( licenseKeyFormatting("a-a-a-a-", 1)) // A-A-A-A
Given a string and an integer k, you need to reverse the first k characters for every segment of length 2k characters counting from the start of the string. If there are less than k characters left, reverse all of them. If there are less than 2k but greater than or equal to k characters, then reverse the first k characters and left the other as original.
Example
Input: s = "abcdefg", k = 2
Output: "bacdfeg"
In the above example, the first chunk of two "ab" was reversed to "ba" and the third chunk of two "ef" was reversed to "fe".
This is my approach:
var reverseStr = function(s, k) {
for (let i = 0; i < k; i++) {
let temp = s[i];
s[i] = s[k - i - 1];
s[k - i - 1] = temp
}
return s
};
console.log(reverseStr("abcdefg", 2))
How do I produce the desired output?
One option is to use a regular expression to match up to k characters, followed by up to 2k characters - then use a replacer function to reverse only the initial k characters:
var reverseStr = function(s, k) {
const pattern = new RegExp(`(.{1,${k}})(.{0,${k}})`, 'g');
return s.replace(pattern, (_, g1, g2) => [...g1].reverse().join('') + g2);
};
console.log(reverseStr("abcdefg", 2))
Strings in JavaScript are immutable, you can't assign to their indexes to modify the string in place. You need to build a new string and return it.
You need a loop for each 2k group. Extract that substring, reverse the first k characters, then concatenate them to the result.
function reverseStr(s, k) {
let result = "";
for (let i = 0; i < s.length; i += 2*k) {
let chunk1 = s.substr(i, k);
// reverse first half
chunk1 = chunk1.split("").reverse().join("");
let chunk2 = s.substr(i+k, k);
result += chunk1 + chunk2;
}
return result;
}
console.log(reverseStr("12345678", 2));
You can realize it in three steps. First separate the string into k group. Then reverse the string of each group at an even index. Last join all the group together.
function reverseStr(s, k) {
return s
.replace(new RegExp('\\w{' + k + '}', 'g'), $2 => $2 + '|')
.split('|')
.map((item, i) =>
i % 2 !== 0
? item
: item
.split('')
.reverse()
.join('')
)
.join('');
}
console.log(reverseStr('abcdefg', 2));
Reverse string in chunks of size k
//make a variable string with some letters to test.
let str = "abcdefg";
//k represents is the number of letters to reverse starting at 0 to position k
let k = 4;
//select the first k letters and split on blankstring, converting to a list
//then reversing that list, collapsing it to a string with join, then
//re-append the original string at position k to the end.
result = (str.substring(0,k).split('')).reverse().join('') + str.substring(k);
console.log({result});
Prints:
{ result: 'dcbaefg' }
I have the following while loop as part of my text justify function. The idea is that I have text strings (str) that need to be justified (spaces added to existing spaces in between words) to equal to a given length (len)
The catch is I can only add one space to an existing space at a time before I iterate over to the next space in the string and add another space there. If that's it for all spaces in the string and it's still not at the required length, I cycle back over to the original space (now two spaces) and add another. Then it goes to the next space between words and so on and so on. The idea is that any spaces between words in the string should not have a differential of more than one space (i.e. Lorem---ipsum--dolor--sit, not Lorem----ipsum--dolor-sit)
From my research, I decided that using a substring method off the original string to add that first extra space, then I will increment the index and move to the next space in the string and repeat the add. Here's my code:
var indexOf = str.indexOf(" ", 0);
if ( indexOf > -1 ) {
while ( indexOf > -1 && str.length < len ) {
//using a regexp to find a space before a character
var space = /\s(?=\b)/.exec(str);
str = str.substring(0, indexOf + 1) + " " + str.substring(indexOf + 1);
//go to next space in string
indexOf = str.indexOf(space, indexOf + 2);
if ( indexOf === -1 ) {
//loops back to beginning of string
indexOf = str.indexOf(space, 0);
}
}
}
finalResults.push(str);
This code works most of the time, but I noticed that there are instances where the cycle of spacing is not correct. For example, it generates the following string:
sit----amet,--blandit
when the correct iteration would be
sit---amet,---blandit
Any assistance in making this code properly iterate over every space (to add one space) in the string once, then cycling back around to the beginning of the string to start over until the desired length is achieved would be most appreciated.
I think it's more efficient to compute the number spaces required in the beginning.
var s = "today is a friday";
var totalLength = 40;
var tokens = s.split(/\s+/);
var noSpaceLength = s.replace(/\s+/g,'').length;
var minSpace = Math.floor((totalLength - noSpaceLength)/(tokens.length-1));
var remainder = (totalLength - noSpaceLength) % (tokens.length-1);
var out = tokens[0];
for (var i = 1; i < tokens.length; i++) {
var spaces = (i <= remainder ? minSpace+1 : minSpace);
out += "-".repeat(spaces) + tokens[i];
}
$('#out').text(out);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="out"></div>
This solution
splits the string (s) into words in an array (a)
finds the number of spaces to be added between all words (add)
finds the remainder of spaces to be added between first words (rem)
then sticks the words with add spaces + one if rem is not exhausted
Code
var s = "Caballo sin Nombre"; // assume one space between words
var len = 21; // desired length
var need = len - s.length;
var a = s.split(/ /); // split s
// need>0 and at least two words
if (need > 0 && a.length>1) {
var add = Math.floor(need / (a.length-1)) + 1; // all spaces need that (+existing)
var rem = need % (a.length-1); // remainder
var sp = '';
while (add-- > 0) sp += ' ';
// replace
var i,res = ''; // result
for (i=0 ; i<a.length-1 ; i++) {
res += a[i] + sp;
if (rem-- > 0) res += ' '; // remainder
}
res += a[i];
s = res;
}
console.log("'" + s + "' is " + s.length + " chars long.");
This function adds the spaces using a global replace, carefully limiting the text size.
function expand (txt, colwidth) {
txt = txt.replace (/\s\s+/, ' '); // Ensure no multiple spaces in txt
for (var spaces = ' ', // Spaces to check for
limit = colwidth - txt.length; // number of additional spaces required
limit > 0; // do while limit is positive
spaces += ' ') // add 1 to spaces to search for
txt = txt.replace (RegExp (spaces, 'g'),
function (r) {
// If limit > 0 then add a space else do not.
return limit > 0 && --limit ? r + ' ' : r
});
return txt;
}
for (var w = 21; w--;) console.log (expand ('this is a test.', w));
Shows this on console:
this is a test.
this is a test.
this is a test.
this is a test.
14 this is a test.
I have string looking like this:
01
02
03
99
I'd like to parse these to make them into strings like:
1. 2. 3. 99. etc.
The numbers are a maximum of 2 characters. Also I have to parse some more numbers later in the source string so I would like to learn the substring equivalent in javascript. Can someone give me advice on how I can do. Previously I had been doing it in C# with the following:
int.Parse(RowKey.Substring(0, 2)).ToString() + "."
Thanks
Why, parseInt of course.
// Add 2 until end of string
var originalA = "01020399";
for (var i = 0; i < originalA.length; i += 2)
{
document.write(parseInt(originalA.substr(i, 2), 10) + ". ");
}
// Split on carriage returns
var originalB = "01\n02\n03\n99";
var strArrayB = originalB.split("\n");
for (var i = 0; i < strArrayB.length; i++)
{
document.write(parseInt(strArrayB[i], 10) + ". ");
}
// Replace the leading zero with regular expressions
var originalC = "01\n02\n03\n99";
var strArrayC = originalC.split("\n");
var regExpC = /^0/;
for (var i = 0; i < strArrayC.length; i++)
{
document.write(strArrayC[i].replace(regExpC, "") + ". ");
}
The other notes are that JavaScript is weakly typed, so "a" + 1 returns "a1". Additionally, for substrings you can choose between substring(start, end) and substr(start, length). If you're just trying to pull a single character, "abcdefg"[2] will return "c" (zero-based index, so 2 means the third character). You usually won't have to worry about type-casting when it comes to simple numbers or letters.
http://jsfiddle.net/mbwt4/3/
use parseInt function.
parseInt(09) //this will give you 9
var myString = parseInt("09").toString()+". "+parseInt("08").toString();
string = '01\n02\n03\n99';
array = string.split('\n');
string2 = '';
for (i = 0; i < array.length; i++) {
array[i] = parseInt(array[i]);
string2 += array[i] + '. ';
}
document.write(string2);
var number = parseFloat('0099');
Demo
Substring in JavaScript works like this:
string.substring(from, to);
where from is inclusive and to is exclusive. You can also use slice:
string.slice(from, to)
where from is inclusive and to is exclusive. The difference between slice and substring is with slice you can specify negative numbers. For example, from = -1 indicates the last character. from(-1, -3) would give you the last 2 characters of the string.
With both methods if you don't specify end then you will get all the characters to the end.
Paul
Ii they are always 2 digits how about;
var s = "01020399";
var result = []
for (var i = 0; i < s.length; i+=2)
result.push(parseInt(s.substr(i, 2), 10) + ".")
alert( result[2] ) // 3.
alert( result.join(" ") ) // 1. 2. 3. 99.