Assign integers from dictionary values to characters of a string - javascript

indices and for value in nicely gives me the loop I'm looking for however I need to go a step further and assign the values of the dictionary to the matching characters of the string then perform calculation for score.
I'd like to know the most Swifty way to accomplish this. Is this possible using map? let curChar = n.map({ print($0) }).
The other issue is that Javascript lets you used heterogeneous dictionaries of type easily but with Swift we need to match types.
var dict: [String:Any] = ["a":1, "j":1, "s":1, "b":2, "k":2,"r":9/*...*/]
let n = "lighthouse"
var nScore = 0
for i in n.indices[n.startIndex..<n.endIndex] {
let curChar = n[i]
var curVal = dict[curChar]
nScore = nScore + curVal
The original Javascript block.
var dict = {A:1, J:1, S:1, B:2, K:2, T:2...};
var n = "lighthouse";
var nScore = 0;
for( var i = 0; i < n.length; i++ );
{
var curChar = n.charAt( i );
var curVal = dict[ curChar ];
nScore = nScore + curVal;
}

n[i] is of type Character, so that should be the key type
of the dictionary instead of String. The value type should be Int:
let dict: [Character: Int] = ["a": 1, "j": 1, "s": 1, "b": 2, "k": 2, "r": 9 /* ... */]
You also have to define a "default value" which is used as score
for characters not found in the dictionary, this can be done
with the nil-coalescing operator ??:
let n = "lighthouse"
var nScore = 0
for i in n.indices[n.startIndex..<n.endIndex] {
let curChar = n[i]
let curVal = dict[curChar] ?? 0
nScore = nScore + curVal
}
Or simpler, by enumerating the characters of the string directly:
for c in n {
let curVal = dict[c] ?? 0
nScore = nScore + curVal
}
Even shorter with reduce():
let n = "lighthouse"
let nScore = n.reduce(0) { (score, c) in
score + (dict[c] ?? 0)
}
which can be written more compactly using "shorthand parameters":
let n = "lighthouse"
let nScore = n.reduce(0) { $0 + (dict[$1] ?? 0) }
If it you have full control over the possible characters which can
occur in the input string, and it is guaranteed(!) the dictionary
defines values for all of them then you can force-unwrap the dictionary lookup, for example
let n = "lighthouse"
let nScore = n.reduce(0) { $0 + dict[$1]! }
But this will crash at runtime if a character is not found.
If you define a function
func numericScore(_ str: String) -> Int {
return str.reduce(0) { $0 + (dict[$1] ?? 0) }
}
then you can easily apply it to a single string
let nScore = numericScore("lighthouse")
or map it over an array of strings
let words = ["lighthouse", "motorcycle"]
let scores = words.map(numericScore)
or compute the total score for an array of strings (using reduce again):
let words = ["lighthouse", "motorcycle"]
let totalScore = words.reduce(0) { $0 + numericScore($1) }
// Alternatively in two steps:
let scores = words.map(numericScore)
let totalScores = scores.reduce(0, +)

Related

Getting wrong elements in an array after comparing two array values

I have two arrays villanStrength = [112,243,512,343,90,478] and playerStrength = [5,789,234,400,452,150] of same length, I am comparing each value of array playerStrength with villanStrength and forming up an another array which will store the either 0 or 1 (false or true) based on comparison, but the output array I am getting is not desirable. Please help me...
my code:
process.stdin.resume();
process.stdin.setEncoding('ascii');
var userInput = //providing this externally from the file
1
6
112 243 512 343 90 478
5 789 234 400 452 150;
var testCases = "";
var numberOfPlayers = "";
var villanStrength = [];
var playerStrength = [];
process.stdin.on('data', (data) => {
userInput = data;
// console.log("user input = " + userInput);
let res = userInput.split("\n");
testCases = res[0];
// for (i=1; i<=testCases; i++) {
numberOfPlayers = res[1];
// console.log("cases = " + testCases);
// console.log("number of players = " + numberOfPlayers);
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
console.log("villan Strength = " + villanStrength);
console.log("player Strength = " + playerStrength);
let isSmall = false;
let comparisonResult = [];
for (let j=0; j<villanStrength.length; j++) {
for (let k=0; k<playerStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[k] = 1; //true = 1, false = 0
} else {
comparisonResult[k] = 0;
}
}
console.log("comparison result for " + j +":" + comparisonResult);
if(comparisonResult.find((findOne) => {return findOne = 1;} )) {
isSmall = true;
console.log("LOSE");
break;
}
}
if (isSmall === false) {
console.log("Win");
}
// }
});
The output array is comparisonResult[] and the values inside comparisonResult I am getting is as below:
villan Strength = 112,243,512,343,90,478
player Strength = 5,789,234,400,452,150
comparison result for 0: 0,0,1,0,1,0 //this should be 1,1,1,1,1,1
comparison result for 1: 0,0,0,0,1,0
comparison result for 2: 0,1,1,1,1,1
comparison result for 3: 0,0,1,0,1,1
comparison result for 4: 0,0,1,0,1,1
comparison result for 5: 0,1,1,1,1,1
in the above result it is expected that the 'comparison result for 0' should be [1,1,1,1,1,1] but it is [0,0,1,0,1,0].
There are a couple problems with this code.
When you compare values in your arrays, you are comparing strings, not numbers. The values you get from stdin are text values, not numeric values. So, for example '5' > '100'. I presume this is the major source of your issue. If you want to do numeric comparisons, you need to convert the strings to numbers.
You are assuming that you get ALL your data on the first data event. While that may usually be true, it is not guaranteed and you should not rely on it when programming. You have to collect data in one or more data events until you have a full chunk of data you can process.
If you add these two log statements that show the actual contents of the array (not the .toString() conversion of the array):
console.log("villan strength: ", villanStrength);
console.log("player strength: ", playerStrength);
You will see this output:
villan strength: [ '112', '243', '512', '343', '90', '478\r' ]
player strength: [ '5', '789', '234', '400', '452', '150;\r' ]
Note, these are strings and when coming from my text file, there's a trailing \r too.
If you change this:
villanStrength = res[2].split(" ");
playerStrength = res[3].split(" ");
to this:
villanStrength = res[2].split(" ").map(item => parseInt(item.trim(), 10));
playerStrength = res[3].split(" ").map(item => parseInt(item.trim(), 10));
Then, it will trim off the newline and convert them to numbers and your comparisons will make sense. This is why the code you posted originally in your question did not generate the wrong output because you hacked in an array of numbers (for purposes of the original question), but your original code was ending up with an array of strings.
Based on your requirement, the playerStrength loop needs to be the outer loop and comparisonResult should be an array of arrays
villanStrength = [112,243,512,343,90,478]
playerStrength = [5,789,234,400,452,150]
// ...
let comparisonResult = []; //output array
for (let j=0; j< playerStrength.length; j++) {
comparisonResult[j] = [];
for (let k=0; k<villanStrength.length; k++) {
if (playerStrength[j] < villanStrength[k]) {
comparisonResult[j].push(1); //true = 1, false = 0
} else {
comparisonResult[j].push(0);
}
}
console.log("comparison result for player " + j +":" + comparisonResult[j]);
}
If I understand the question right you need to compare each value from array1 to array2 and generate a new array that show diffrent...
All you need is just one loop that can take both values and push result of comparison to another array
function compare() {
const villanStrength = [112, 243, 512, 343, 90, 478];
const playerStrength = [5, 789, 234, 400, 452, 150];
const result = [];
for (let i = 0; i < villanStrength.length; i++) {
const vVal = villanStrength[i];
const pVal = playerStrength[i];
if (pVal < vVal) {
result.push(1);
continue;
}
result.push(0);
}
console.log(result);
}
My suggestion for is to separate codes to smaller funtions so you can focus on each section

Take a string , evaluate it and find if there is a number and repeat part of string that number of times?

I was writing code and came into this problem,
You have a specific string which is in this form:
d ae2 n s
now we have to decode this in a specific way,
Split it into different parts by spaces to make an array like ["d","ae2","n","s"]
Evaluate each element of the array and find out if there is a number in it.
If there is a number then repeat the string the number of times.
Add it into the array and continue.
So the output array should be
["d","ae","ae","n","s"]
I have already tried a lot but got nothing
I have used this code earlier but it ends on the second string:
var str = "d ae2 n s"
var res = str.split(" ");
alert(res.length);
for(var x = 0; x < res.length; x++ ){
var std = res[x];
var fun = checkNum(std);
if(fun === true){
var numbers = str.match(/\d+/g).map(Number);
var index = res.indexOf(std);
var result = std.replace(/[0-9]/g, '');
var res2 = result.repeat(numbers);
res[index] = res2;
}
else{
continue;
}
for(var i = 0; i < res.length; i++ ){
console.log(res[x]);
}
}
function checkNum(t){
return /\d/.test(t);
}
// I am a terible coder :/
expected input : d ae2 n s
expected output : ["d","ae","ae","n","s"]
Using fill() and flatMap() methods and
regex replace
/[^0-9]/ - all non numerical chars
/[0-9]/ - all numerical chars
var str = 'd ae2 n s'
var res = str
.split(' ')
.flatMap(i =>
Array(+i.replace(/[^0-9]/g, '') || 1)
.fill(i.replace(/[0-9]/g, ''))
)
console.log(res)
You can simply loop over your array and populate an other array that will hold your result after checking for a number :
const results = [];
"d ae2 n s".split(' ').forEach(token => {
const match = token.match(/\d+/);
if (match) {
const newStr = token.split(/\d/)[0];
for (let i = 0; i < match[0]; i++) {
results.push(newStr);
}
} else {
results.push(token)
}
})
console.log(results);
You can check Seblor's answer for optimized logic. I have modified your code so that it will be easy for you to understand where you went wrong while doing this. I have added comments to your code where I have changed things:
var str = "d ae2 n s"
var res = str.split(" ");
// create a variable to store the output.
var output = [];
for(var x = 0; x < res.length; x++ ){
var std = res[x];
var fun = checkNum(std);
if(fun === true){
// map returns an array, so take the first element, it will be your number.
var numbers = str.match(/\d+/g).map(Number)[0];
var index = res.indexOf(std);
var result = std.replace(/[0-9]/g, '');
// instead of doing the repeat and updating the current index,
// push the result, i.e. the current string to be repeated "numbers" times into
// the output array.
for (var i = 0; i < numbers; i++) {
output.push(result)
}
}
else{
// if does not contain any number, push the current item to ouput
output.push (std);
continue;
}
}
function checkNum(t){
return /\d/.test(t);
}
console.log(output);
You can do:
const str1 = 'd ae2 n s';
const str2 = 'e d aefg4 m n s';
const regex = /\d+/;
const getResult = input => input.split(' ').reduce((a, c) => {
const n = c.match(regex);
return n
? [...a.concat(c.replace(n, ' ').repeat(n).trim().split(' '))]
: [...a, c];
}, []);
console.log(getResult(str1));
console.log(getResult(str2));
you can use the Array prototype reduce and filter
const input = 'd ae2 n s';
const output = input.split(' ').reduce((memory, current) => {
const numberIndex = current.split('').findIndex(c => !isNaN(c));
const newCurrent = current.split('').filter((_, index) => index !== numberIndex).join('');
if(numberIndex !== -1) {
for(let i = 0; i < parseInt(current[numberIndex]); i++) {
memory.push(newCurrent);
}
} else {
memory.push(current);
}
return memory;
}, []);
console.log(output);
Hope this helped
You can try with following:
let str = "d ae2 n s"
let split = str.split(" ")
let rx = new RegExp("[0-9]")
let res = [];
split.forEach(s => {
if(rx.exec(s) !== null) {
let rxResult = rx.exec(s)
let count = rxResult[0];
let matchIdx = rxResult[1];
for(let i = 0; i < count; i++) {
res.push(s.replace(count, ""))
}
} else {
res.push(s);
}
})

Alibaba interview: print a sentence with min spaces

I saw this interview question and gave a go. I got stuck. The interview question is:
Given a string
var s = "ilikealibaba";
and a dictionary
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
try to give the s with min space
The output may be
i like alibaba (2 spaces)
i like ali baba (3 spaces)
but pick no.1
I have some code, but got stuck in the printing.
If you have better way to do this question, let me know.
function isStartSub(part, s) {
var condi = s.startsWith(part);
return condi;
}
function getRestStr(part, s) {
var len = part.length;
var len1 = s.length;
var out = s.substring(len, len1);
return out;
}
function recPrint(arr) {
if(arr.length == 0) {
return '';
} else {
var str = arr.pop();
return str + recPrint(arr);
}
}
// NOTE: have trouble to print
// Or if you have better ways to do this interview question, please let me know
function myPrint(arr) {
return recPrint(arr);
}
function getMinArr(arr) {
var min = Number.MAX_SAFE_INTEGER;
var index = 0;
for(var i=0; i<arr.length; i++) {
var sub = arr[i];
if(sub.length < min) {
min = sub.length;
index = i;
} else {
}
}
return arr[index];
}
function rec(s, d, buf) {
// Base
if(s.length == 0) {
return;
} else {
}
for(var i=0; i<d.length; i++) {
var subBuf = [];
// baba
var part = d[i];
var condi = isStartSub(part, s);
if(condi) {
// rest string
var restStr = getRestStr(part, s);
rec(restStr, d, subBuf);
subBuf.unshift(part);
buf.unshift(subBuf);
} else {
}
} // end loop
}
function myfunc(s, d) {
var buf = [];
rec(s, d, buf);
console.log('-- test --');
console.dir(buf, {depth:null});
return myPrint(buf);
}
// Output will be
// 1. i like alibaba (with 2 spaces)
// 2. i like ali baba (with 3 spaces)
// we pick no.1, as it needs less spaces
var s = "ilikealibaba";
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
var out = myfunc(s, d);
console.log(out);
Basically, my output is, not sure how to print it....
[ [ 'i', [ 'like', [ 'alibaba' ], [ 'ali', [ 'baba' ] ] ] ] ]
This problem is best suited for a dynamic programming approach. The subproblem is, "what is the best way to create a prefix of s". Then, for a given prefix of s, we consider all words that match the end of the prefix, and choose the best one using the results from the earlier prefixes.
Here is an implementation:
var s = "ilikealibaba";
var arr = ["i", "like", "ali", "liba", "baba", "alibaba"];
var dp = []; // dp[i] is the optimal solution for s.substring(0, i)
dp.push("");
for (var i = 1; i <= s.length; i++) {
var best = null; // the best way so far for s.substring(0, i)
for (var j = 0; j < arr.length; j++) {
var word = arr[j];
// consider all words that appear at the end of the prefix
if (!s.substring(0, i).endsWith(word))
continue;
if (word.length == i) {
best = word; // using single word is optimal
break;
}
var prev = dp[i - word.length];
if (prev === null)
continue; // s.substring(i - word.length) can't be made at all
if (best === null || prev.length + word.length + 1 < best.length)
best = prev + " " + word;
}
dp.push(best);
}
console.log(dp[s.length]);
pkpnd's answer is along the right track. But word dictionaries tend to be quite large sets, and iterating over the entire dictionary at every character of the string is going to be inefficient. (Also, saving the entire sequence for each dp cell may consume a large amount of space.) Rather, we can frame the question, as we iterate over the string, as: given all the previous indexes of the string that had dictionary matches extending back (either to the start or to another match), which one is both a dictionary match when we include the current character, and has a smaller length in total. Generally:
f(i) = min(
f(j) + length(i - j) + (1 if j is after the start of the string)
)
for all j < i, where string[j] ended a dictionary match
and string[j+1..i] is in the dictionary
Since we only add another j when there is a match and a new match can only extend back to a previous match or to the start of the string, our data structure could be an array of tuples, (best index this match extends back to, total length up to here). We add another tuple if the current character can extend a dictionary match back to another record we already have. We can also optimize by exiting early from the backwards search once the matched substring would be greater than the longest word in the dictionary, and building the substring to compare against the dictionary as we iterate backwards.
JavaScript code:
function f(str, dict){
let m = [[-1, -1, -1]];
for (let i=0; i<str.length; i++){
let best = [null, null, Infinity];
let substr = '';
let _i = i;
for (let j=m.length-1; j>=0; j--){
let [idx, _j, _total] = m[j];
substr = str.substr(idx + 1, _i - idx) + substr;
_i = idx;
if (dict.has(substr)){
let total = _total + 1 + i - idx;
if (total < best[2])
best = [i, j, total];
}
}
if (best[0] !== null)
m.push(best);
}
return m;
}
var s = "ilikealibaba";
var d = new Set(["i", "like", "ali", "liba", "baba", "alibaba"]);
console.log(JSON.stringify(f(s,d)));
We can track back our result:
[[-1,-1,-1],[0,0,1],[4,1,6],[7,2,10],[11,2,14]]
[11, 2, 14] means a total length of 14,
where the previous index in m is 2 and the right index
of the substr is 11
=> follow it back to m[2] = [4, 1, 6]
this substr ended at index 4 (which means the
first was "alibaba"), and followed m[1]
=> [0, 0, 1], means this substr ended at index 1
so the previous one was "like"
And there you have it: "i like alibaba"
As you're asked to find a shortest answer probably Breadth-First Search would be a possible solution. Or you could look into A* Search.
Here is working example with A* (cause it's less bring to do than BFS :)), basically just copied from Wikipedia article. All the "turning string into a graph" magick happens in the getNeighbors function
https://jsfiddle.net/yLeps4v5/4/
var str = 'ilikealibaba'
var dictionary = ['i', 'like', 'ali', 'baba', 'alibaba']
var START = -1
var FINISH = str.length - 1
// Returns all the positions in the string that we can "jump" to from position i
function getNeighbors(i) {
const matchingWords = dictionary.filter(word => str.slice(i + 1, i + 1 + word.length) == word)
return matchingWords.map(word => i + word.length)
}
function aStar(start, goal) {
// The set of nodes already evaluated
const closedSet = {};
// The set of currently discovered nodes that are not evaluated yet.
// Initially, only the start node is known.
const openSet = [start];
// For each node, which node it can most efficiently be reached from.
// If a node can be reached from many nodes, cameFrom will eventually contain the
// most efficient previous step.
var cameFrom = {};
// For each node, the cost of getting from the start node to that node.
const gScore = dictionary.reduce((acc, word) => { acc[word] = Infinity; return acc }, {})
// The cost of going from start to start is zero.
gScore[start] = 0
while (openSet.length > 0) {
var current = openSet.shift()
if (current == goal) {
return reconstruct_path(cameFrom, current)
}
closedSet[current] = true;
getNeighbors(current).forEach(neighbor => {
if (closedSet[neighbor]) {
return // Ignore the neighbor which is already evaluated.
}
if (openSet.indexOf(neighbor) == -1) { // Discover a new node
openSet.push(neighbor)
}
// The distance from start to a neighbor
var tentative_gScore = gScore[current] + 1
if (tentative_gScore >= gScore[neighbor]) {
return // This is not a better path.
}
// This path is the best until now. Record it!
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
})
}
throw new Error('path not found')
}
function reconstruct_path(cameFrom, current) {
var answer = [];
while (cameFrom[current] || cameFrom[current] == 0) {
answer.push(str.slice(cameFrom[current] + 1, current + 1))
current = cameFrom[current];
}
return answer.reverse()
}
console.log(aStar(START, FINISH));
You could collect all possible combinations of the string by checking the starting string and render then the result.
If more than one result has the minimum length, all results are taken.
It might not work for extrema with string who just contains the same base string, like 'abcabc' and 'abc'. In this case I suggest to use the shortest string and update any part result by iterating for finding longer strings and replace if possible.
function getWords(string, array = []) {
words
.filter(w => string.startsWith(w))
.forEach(s => {
var rest = string.slice(s.length),
temp = array.concat(s);
if (rest) {
getWords(rest, temp);
} else {
result.push(temp);
}
});
}
var string = "ilikealibaba",
words = ["i", "like", "ali", "liba", "baba", "alibaba"],
result = [];
getWords(string);
console.log('all possible combinations:', result);
console.log('result:', result.reduce((r, a) => {
if (!r || r[0].length > a.length) {
return [a];
}
if (r[0].length === a.length) {
r.push(a);
}
return r;
}, undefined))
Use trie data structure
Construct a trie data structure based on the dictionary data
Search the sentence for all possible slices and build a solution tree
Deep traverse the solution tree and sort the final combinations
const sentence = 'ilikealibaba';
const words = ['i', 'like', 'ali', 'liba', 'baba', 'alibaba',];
class TrieNode {
constructor() { }
set(a) {
this[a] = this[a] || new TrieNode();
return this[a];
}
search(word, marks, depth = 1) {
word = Array.isArray(word) ? word : word.split('');
const a = word.shift();
if (this[a]) {
if (this[a]._) {
marks.push(depth);
}
this[a].search(word, marks, depth + 1);
} else {
return 0;
}
}
}
TrieNode.createTree = words => {
const root = new TrieNode();
words.forEach(word => {
let currentNode = root;
for (let i = 0; i < word.length; i++) {
currentNode = currentNode.set(word[i]);
}
currentNode.set('_');
});
return root;
};
const t = TrieNode.createTree(words);
function searchSentence(sentence) {
const marks = [];
t.search(sentence, marks);
const ret = {};
marks.map(mark => {
ret[mark] = searchSentence(sentence.slice(mark));
});
return ret;
}
const solutionTree = searchSentence(sentence);
function deepTraverse(tree, sentence, targetLen = sentence.length) {
const stack = [];
const sum = () => stack.reduce((acc, mark) => acc + mark, 0);
const ret = [];
(function traverse(tree) {
const keys = Object.keys(tree);
keys.forEach(key => {
stack.push(+key);
if (sum() === targetLen) {
const result = [];
let tempStr = sentence;
stack.forEach(mark => {
result.push(tempStr.slice(0, mark));
tempStr = tempStr.slice(mark);
});
ret.push(result);
}
if(tree[key]) {
traverse(tree[key]);
}
stack.pop();
});
})(tree);
return ret;
}
const solutions = deepTraverse(solutionTree, sentence);
solutions.sort((s1, s2) => s1.length - s2.length).forEach((s, i) => {
console.log(`${i + 1}. ${s.join(' ')} (${s.length - 1} spaces)`);
});
console.log('pick no.1');

How to get longest substring from array of strings using javascript

I have array:
let arr = ["logerror", "log:today", "log:1"]
I am looking for function how to get longest substring from this items.
Result:
log
Another example:
let arr = ["dog+ěě+", "dog15qwqqq", "dogggggg"]
Result:
dog
Sure, I can write some algorithm, but is there any simple way?
How? Thanks
If you can phrase your question succinctly, you can often find what to search for. In this case, it looks like:
"Find the longest common substring from within an array of strings"
A quick google reveals an algorithm for finding the largest common substring between two strings:
https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Longest_common_substring
I don't want to copy the code as written there, as unsure of the copyright, but you could take the implementation and take something that will work with your array.
I would note that for large arrays, this may turn out to be a lengthy operation...
I used a simple approach:
It sorts the array using sort() method.
Then, the most important step is to look just at the first and last items.
function commonSubsequence(array){
let sortedArray = array.sort();
let first = sortedArray[0];
let last = sortedArray.pop();
let length = first.length;
let index = 0;
while(index<length && first[index] === last[index])
index++;
return first.substring(0, index);
}
console.log(commonSubsequence(["logerror", "log:today", "log:1"]));
console.log(commonSubsequence(["dog+ěě+", "dog15qwqqq", "dogggggg"]));
Here is my suggestion
function subStrArr(arr) {
let chars = arr[0].split(""), sub = "";
for (let i=0;i<chars.length;i++) {
for (let j=1;j<arr.length;j++) {
if (arr[j].indexOf(chars[i])==-1) return sub;
}
sub+=chars[i];
}
}
let arr1 = ["logerror", "log:today", "log:1"];
let arr2 = ["dog+ěě+", "dog15qwqqq", "dogggggg"];
console.log(subStrArr(arr1))
console.log(subStrArr(arr2))
After some looking around I went for the string-algorithms npm package, which did the job nicely for me.
From the docs:
import { longestCommonSubstring } from 'string-algorithms';
const strings = [
'12apple',
'3apple4',
'apple56'
];
console.log(longestCommonSubstring(strings));
produces the output apple.
without DP approach
var lcs = function (n, m) {
let lcs = 0 //to store longest common substring
let s1 = n.length
let s2 = m.length
for(let i = 0;i < s1;i++){
for(let j = 0; j< s2;j++){
let track = 0
//if letter are same, do while to check next letter
if(n[i] == m[j]){
while(i + track < s1 && j + track < s2 && n[i + track] == m[j + track]){
track += 1 // to track
if (lcs < track) {
lcs += 1
}
}
}
}
}
return lcs;
};
var m = "abcdxyz"
var n = "xyzabcd" // 4
// var m = "dadef"
// var n = "adwce"//2
// var m = "acdghr";
// var n = "bgh"; //2
// var m = "A"
// var n = "A" //1
console.log(lcs(m, n));

How can I slice a number into smaller digits to fit my array

I am making a counter which will show the sum of dice rolled. At the moment if i go over 9 it turns into zero. I need to slice up the number of zeroValue into one digit long sections. so 123 becomes 1 23, 1 2 3, 12 3. So that it fits into my array. I tried something like this:
function diceResult(){
var whichNumber = 123; // this number will change, depending on sum of dice rolled
var getTextNumber = new Array (9)
getTextNumber[0] = "zero";
getTextNumber[1] = "one";
getTextNumber[2] = "two";
getTextNumber[3] = "three";
getTextNumber[4] = "four";
getTextNumber[5] = "five";
getTextNumber[6] = "six";
getTextNumber[7] = "seven";
getTextNumber[8] = "eight";
getTextNumber[9] = "nine";
var zeroValue = getTextNumber[whichNumber];
var getZero = diceToolbarCounterWrapper.getElementsByTagName("li");
getZero[2].className = zeroValue.slice(2, -0; /* <------ I tried this */
getZero[1].className = zeroValue.slice(1, -1);
getZero[0].className = zeroValue.slice(0, -1);
};
Unfortunately this doesn't work. Another problem with this is that if the number is under 3 digits long it removes too many digits. This is what I want to happen if the sum of dice rolled is 123:
getZero[2].className = "one";
getZero[1].className = "two";
getZero[0].className = "three";
How can I achieve this? Please add code to your answer as I am new to javaScript.
You can go through the string character by character and do what you need
var num = 123;
var str_num = num.toString();
for(var i = 0; i < str_num.length ; i++){
console.log(str_num[i]);
// if you need int
console.log(parseInt(str_num[i]));
}
One possibility is to split the number:
function splitNum (n) {
var digits = [n % 10];
n = Math.floor(n / 10);
return n == 0 ? digits : (
splitNum(n).concat(digits)
);
}
splitNum(0) // [0]
splitNum(1) // [1]
splitNum(12) // [1, 2]
Then to pad the array with a couple of zeros:
function zeroPad (n, digits) {
var zeros = new Array(n);
while (n--) zeros[n] = 0;
return zeros.concat(digits);
}
digits = splitNum(12); // [1, 2]
zeros = 3 - digits.length; // 1
digits = zeroPad(zeros, digits); // [0, 1, 2]
There is a shortcut though (ninjavascript):
num = 12 + ""; // "12"
num = new Array(4 - num.length).join("0") + num; // "012"
digits = num.split(""); // ["0", "1", "2"]
digits = digits.map(Number); // [0, 1, 2]
It might help you understand what's going on if you give you variables meaningful names. Here's how your code reads if you do that:
function diceResult(){
var roll = 123; // this number will change, depending on sum of dice rolled
var words= new Array (9)
words[0] = "zero";
words[1] = "one";
words[2] = "two";
words[3] = "three";
words[4] = "four";
words[5] = "five";
words[6] = "six";
words[7] = "seven";
words[8] = "eight";
words[9] = "nine";
var word = getTextNumber[num];
var list = diceToolbarCounterWrapper.getElementsByTagName("li");
list[2].className = word.slice(2, -0; /* <------ I tried this */
list[1].className = word.slice(1, -1);
list[0].className = word.slice(0, -1);
};
}
Now you should be able to see that you're slicing up the wrong thing. You want to use one of the digits from roll as an index into words. There are lots of ways of getting the digits from your number, but this is the simplest
(roll + '').split('')
This takes your number and turns it into a string (by adding it to a string), then splits it into an array of strings.
Now you need to use parseInt() to get the value to use to dereference your array, so you end up with this:
var nums = (roll+ '').split('')
list[2].className = words[parseInt(nums[0])];
list[1].className = words[parseInt(nums[1])];
list[0].className = words[parseInt(nums[2])];
Of course, you still have the problem of dealing with double digits instead of three, or maybe even four or more, so that becomes this:
var index = (roll + '').split('');
for(i = 0; i < index.length; i++)
list[i].className = words[parseInt(index[list.length - i])];
This loops through the index array setting the class name you want on the list elements you need. The list.length - i bit is because you want them in reverse order.
Here's a runnable snippet demonstrating the technique:
var roll = 43; // this number will change, depending on sum of dice rolled
var words = new Array (9);
words[0] = "zero";
words[1] = "one";
words[2] = "two";
words[3] = "three";
words[4] = "four";
words[5] = "five";
words[6] = "six";
words[7] = "seven";
words[8] = "eight";
words[9] = "nine";
var index = (roll + '').split('');
document.write("<p>Here's the array containing the digits of the roll: [" + index + "]</p><p>And the classes follow</p>");
for(i = 0; i < index.length; i++)
document.write(words[parseInt(index[index.length - 1 - i])] + "<br/>");
As it stands zeroValue will be undefined whenever it is over 9. This is because
var getTextNumber = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
and
getTextNumber[123] === undefined // true.
You would need to split whichNumber before you do the lookup. This is going to get very longhand, e.g. var whichNumber1 = whichNumber.toString().slice(0,1) and so on. Rather than go down that road, I'd recommend using split:
function diceResult(){
var whichNumber = getSumDiceValue(); //sum of dice rolled.
var getTextNumber = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
var splitNumber = whichNumber.toString().split(""); // ["1", "2", "3"]
var getZero = diceToolbarCounterWrapper.getElementsByTagName("li");
getZero[0].className = getTextNumber[splitNumber[0]];
if (splitNumber.length > 1) {
getZero[1].className = getTextNumber[splitNumber[1]]
} else {
getZero[1].className = "";
}
if (splitNumber.length > 2) {
getZero[2].className = getTextNumber[splitNumber[2]];
} else {
getZero[2].className = "";
}
};
Edit: to solve the backwards positioning problem you could rewrite this as:
for (i = splitNumber.length - 1; i >= 0; i--) {
getZero[3 - splitNumber.length + i].className = getTextNumber[splitNumber[i]];
}
if (splitNumber.length === 1) {
getZero[0].className = "";
getZero[1].className = "";
}
if (splitNumber.length === 2) {
getZero[0].className = "";
}
Number to string conversion is very expensive. And getting the digits out might become a problem for some. So here is a very simple solution. I guess this must be very very fast as well.
You can create a very simple function as follows. Well OK.. you may not chose to use the arrow functions and you may not choose declaring the default values etc.. but here is the idea.
var getArr = (n, h = Math.floor(n/100)%10,
t = Math.floor(n/10)%10,
o = n%10) => h != 0 ? [h].concat(t).concat(o)
: t != 0 ? [t].concat(o)
: [o];
document.write("<pre>" + JSON.stringify(getArr(7)) + "</pre>");
document.write("<pre>" + JSON.stringify(getArr(42)) + "</pre>");
document.write("<pre>" + JSON.stringify(getArr(137)) + "</pre>");

Categories

Resources