This question already has answers here:
How do you convert numbers between different bases in JavaScript?
(21 answers)
Closed 1 year ago.
In JavaScript, is there any built-in function for converting an integer from one given base to another given base? I've noticed that it's already possible to convert a decimal number to another base using toString(numberToConvertTo), but I haven't yet found a general-purpose function that can convert from any base to any other base, as shown:
convertFrom(toConvert, baseToConvertFrom, baseToConvertTo){
//convert the number from baseToConvertFrom to BaseToConvertTo
}
Call parseInt(str, fromBase) to convert to base 10 (or rather, to an actual number), then call num.toString(toBase).
You might want to customise your input or output. You might want more than 36 bases. So I made this
function baseCon(number,fromBase,toBase,fromChars,toChars) {
if (!fromChars) {
fromChars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
number = number.toString().toUpperCase();
}
if (!toChars) {
toChars = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
}
if (typeof number != 'object') {
number = number.toString();
}
if (fromBase > fromChars.length) {
console.log('fromBase was too high');
} else if (toBase > toChars.length) {
console.log('toBase was too high');
} else {
if (fromBase == 10) {
var base10Num = Math.min(number);
} else {
var base10Num = 0;
var place = 0;
for (var index = number.length - 1; index > -1; index--) {
base10Num = base10Num + (fromChars.indexOf(number[index]) * Math.pow(fromBase,place));
place++;
}
}
var string = '';
var looping = true;
var stringLen = 0;
var stringVal = 0;
while (looping) {
stringLen++;
if (Math.pow(toBase,stringLen) == base10Num) {
stringLen++;
break;
} else if (Math.pow(toBase,stringLen) >= base10Num) {
break;
}
}
for (var placePos = stringLen; placePos > 0; placePos--) {
for (var placeVal = 0; placeVal < (toBase + 1); placeVal++) {
if (((placeVal * Math.pow(toBase,placePos - 1)) > (base10Num - stringVal)) || (placeVal == 0) && ((base10Num - stringVal) == 0)) {
if (!((placeVal == 0) && ((base10Num - stringVal) == 0))) {
stringVal = stringVal + ((placeVal - 1) * Math.pow(toBase,placePos - 1));
string = string + toChars[placeVal - 1];
} else {
string = string + toChars[0];
}
break;
}
}
}
if (stringVal == base10Num) {
return string;
} else {
console.log('baseCon failed');
return string;
}
}
};
You can customise the input chars so you can do things like this
> baseCon([true,true,false,true,false],2,10,[false,true]);
< "26"
and of coarse the output chars
> baseCon('3942',10,8,false,['!','#','#','$','%','^','&','*']);
< "*^%&"
It took me all day and then I remembered parseInt(number,fromBase).toString(toBase); haha
Related
Here's the question:
A Narcissistic Number is a positive number which is the sum of its own digits, each raised to the power of the number of digits in a given base. In this Kata, we will restrict ourselves to decimal (base 10).
For example, take 153 (3 digits), which is narcisstic:
1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153
Your code must return true or false (not 'true' and 'false') depending upon whether the given number is a Narcissistic number in base 10.
My Code is:
function narcissistic(value) {
let vLen = value.length;
let sum = 0;
for (let i = 0; i < vLen; i++) {
sum += Math.pow(value[i], vLen);
}
if (sum == value) {
return true;
} else {
return false;
}
}
But I'm getting errors. What should I do?
Numbers don't have .length, convert to string first
vLen[i], you cant treat a number as array, again, convert to string to use that syntax.
The return can be simplefied to return (sum === value);
function narcissistic(value) {
let sVal = value.toString();
let vLen = sVal.length;
let sum = 0;
for (let i = 0; i < vLen; i++) {
sum += Math.pow(sVal[i], vLen);
}
return (sum === value);
}
console.log(narcissistic(153));
console.log(narcissistic(111));
Well... There are several things wrong with this code, but I think there is mostly a problem with the types of your input.
I'll show you how you can cast the types of your input to make sure you work with the types you need:
Also... You should try to avoid using the == operator and try to use === instead (same goes for != and !==), because the == and != don't try to match the types, resulting in sometimes unpredictable results
function narcissistic(value) {
valueStr = String(value);
let vLen = valueStr.length;
let sum = 0;
for (let i = 0; i < vLen; i++) {
sum += Number(valueStr[i]) ** vLen;
}
if (sum === value) {
return true;
} else {
return false;
}
}
if(narcissistic(153)) {
console.log("narcissistic(153) is true!") // expected value: true
}
All the first 9 digits from 1 to 9 is Narcissistic number as there length is 1 and there addition is always same.
So, first we are checking weather the number is greater than 9 or not.
if(num>9) =>false than it's a narcissistic number.
-if(num>9) =>true than we have to split number into digits for that I have used x = num.toString().split('');. Which is first converting number to String and than using split() function to split it.
Than , we are looping through each digit and digitsSum += Math.pow(Number(digit), x.length); adding the power of digit to const isNarcissistic = (num) => { let x = 0; let digitsSum.
at the end, we are comparing both num & digitsSum if there are matched than number is narcissistic else not.
const isNarcissistic = (num) => {
let x = 0;
let digitsSum = 0;
if (num > 9) {
x = num.toString().split('');
x.forEach(digit => {
digitsSum += Math.pow(Number(digit), x.length);
});
if (digitsSum == num) {
return true;
} else {
return false;
}
} else {
return true;
}
}
console.log(isNarcissistic(153));
console.log(isNarcissistic(1634));
console.log(isNarcissistic(1433));
console.log(isNarcissistic(342));
This question already has answers here:
How to format numbers as currency strings
(67 answers)
Closed 5 years ago.
I need convert strings to price format.
For example
150 = 150.00
1000 = 1'000.00
25500 = 25'500.00
1000.80 = 1'000.80 etc.
I wrote code but not sure it is good:
function insert(str, index, value) {
return str.substr(0, index) + value + str.substr(index);
}
function convert(n) {
n = n.toString();
var length = n.length;
if (length < 4) {
n = insert(n, length, '.00');
} else if (length === 4) {
n = insert(n, 1, "'");
n = insert(n, length + 1, '.00');
} else if (length > 4) {
var floatFlag = false;
if (n.indexOf('.') > -1 || n.indexOf(',') > -1) {
floatFlag = true;
n = n.replace(/,/g, '.');
}
var thouthandNumer = n / 1000;
thouthandNumer = thouthandNumer | 0;
n = n.replace(thouthandNumer, thouthandNumer + "'");
if (!floatFlag) {
n = insert(n, length + 1, '.00');
}
}
}
var n = 15000
convert(n); //return 15'000.00
How can I convert strings in correct way? Thanks for help.
Use Number.toLocaleString():
let x = 25500;
console.log(x.toLocaleString('en-us', {minimumFractionDigits: 2}));
I'm trying to create a damerau-levenshtein distance function in JS.
I've found a description off the algorithm on WIkipedia, but they is no implementation off it. It says:
To devise a proper algorithm to calculate unrestricted
Damerau–Levenshtein distance note that there always exists an optimal
sequence of edit operations, where once-transposed letters are never
modified afterwards. Thus, we need to consider only two symmetric ways
of modifying a substring more than once: (1) transpose letters and
insert an arbitrary number of characters between them, or (2) delete a
sequence of characters and transpose letters that become adjacent
after deletion. The straightforward implementation of this idea gives
an algorithm of cubic complexity: O\left (M \cdot N \cdot \max(M, N)
\right ), where M and N are string lengths. Using the ideas of
Lowrance and Wagner,[7] this naive algorithm can be improved to be
O\left (M \cdot N \right) in the worst case. It is interesting that
the bitap algorithm can be modified to process transposition. See the
information retrieval section of[1] for an example of such an
adaptation.
https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
The section [1] points to http://acl.ldc.upenn.edu/P/P00/P00-1037.pdf which is even more complicated to me.
If I understood this correctly, it's not that easy to create an implementation off it.
Here's the levenshtein implementation I currently use :
levenshtein=function (s1, s2) {
// discuss at: http://phpjs.org/functions/levenshtein/
// original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
// bugfixed by: Onno Marsman
// revised by: Andrea Giammarchi (http://webreflection.blogspot.com)
// reimplemented by: Brett Zamir (http://brett-zamir.me)
// reimplemented by: Alexander M Beedie
// example 1: levenshtein('Kevin van Zonneveld', 'Kevin van Sommeveld');
// returns 1: 3
if (s1 == s2) {
return 0;
}
var s1_len = s1.length;
var s2_len = s2.length;
if (s1_len === 0) {
return s2_len;
}
if (s2_len === 0) {
return s1_len;
}
// BEGIN STATIC
var split = false;
try {
split = !('0')[0];
} catch (e) {
// Earlier IE may not support access by string index
split = true;
}
// END STATIC
if (split) {
s1 = s1.split('');
s2 = s2.split('');
}
var v0 = new Array(s1_len + 1);
var v1 = new Array(s1_len + 1);
var s1_idx = 0,
s2_idx = 0,
cost = 0;
for (s1_idx = 0; s1_idx < s1_len + 1; s1_idx++) {
v0[s1_idx] = s1_idx;
}
var char_s1 = '',
char_s2 = '';
for (s2_idx = 1; s2_idx <= s2_len; s2_idx++) {
v1[0] = s2_idx;
char_s2 = s2[s2_idx - 1];
for (s1_idx = 0; s1_idx < s1_len; s1_idx++) {
char_s1 = s1[s1_idx];
cost = (char_s1 == char_s2) ? 0 : 1;
var m_min = v0[s1_idx + 1] + 1;
var b = v1[s1_idx] + 1;
var c = v0[s1_idx] + cost;
if (b < m_min) {
m_min = b;
}
if (c < m_min) {
m_min = c;
}
v1[s1_idx + 1] = m_min;
}
var v_tmp = v0;
v0 = v1;
v1 = v_tmp;
}
return v0[s1_len];
}
What are your ideas for building such an algorithm and, if you think it would be too complicated, what could I do to make no difference between 'l' (L lowercase) and 'I' (i uppercase) for example.
The gist #doukremt gave: https://gist.github.com/doukremt/9473228
gives the following in Javascript.
You can change the weights of operations in the weighter object.
var levenshteinWeighted= function(seq1,seq2)
{
var len1=seq1.length;
var len2=seq2.length;
var i, j;
var dist;
var ic, dc, rc;
var last, old, column;
var weighter={
insert:function(c) { return 1.; },
delete:function(c) { return 0.5; },
replace:function(c, d) { return 0.3; }
};
/* don't swap the sequences, or this is gonna be painful */
if (len1 == 0 || len2 == 0) {
dist = 0;
while (len1)
dist += weighter.delete(seq1[--len1]);
while (len2)
dist += weighter.insert(seq2[--len2]);
return dist;
}
column = []; // malloc((len2 + 1) * sizeof(double));
//if (!column) return -1;
column[0] = 0;
for (j = 1; j <= len2; ++j)
column[j] = column[j - 1] + weighter.insert(seq2[j - 1]);
for (i = 1; i <= len1; ++i) {
last = column[0]; /* m[i-1][0] */
column[0] += weighter.delete(seq1[i - 1]); /* m[i][0] */
for (j = 1; j <= len2; ++j) {
old = column[j];
if (seq1[i - 1] == seq2[j - 1]) {
column[j] = last; /* m[i-1][j-1] */
} else {
ic = column[j - 1] + weighter.insert(seq2[j - 1]); /* m[i][j-1] */
dc = column[j] + weighter.delete(seq1[i - 1]); /* m[i-1][j] */
rc = last + weighter.replace(seq1[i - 1], seq2[j - 1]); /* m[i-1][j-1] */
column[j] = ic < dc ? ic : (dc < rc ? dc : rc);
}
last = old;
}
}
dist = column[len2];
return dist;
}
Stolen from here, with formatting and some examples on how to use it:
function DamerauLevenshtein(prices, damerau) {
//'prices' customisation of the edit costs by passing an object with optional 'insert', 'remove', 'substitute', and
//'transpose' keys, corresponding to either a constant number, or a function that returns the cost. The default cost
//for each operation is 1. The price functions take relevant character(s) as arguments, should return numbers, and
//have the following form:
//
//insert: function (inserted) { return NUMBER; }
//
//remove: function (removed) { return NUMBER; }
//
//substitute: function (from, to) { return NUMBER; }
//
//transpose: function (backward, forward) { return NUMBER; }
//
//The damerau flag allows us to turn off transposition and only do plain Levenshtein distance.
if (damerau !== false) {
damerau = true;
}
if (!prices) {
prices = {};
}
let insert, remove, substitute, transpose;
switch (typeof prices.insert) {
case 'function':
insert = prices.insert;
break;
case 'number':
insert = function (c) {
return prices.insert;
};
break;
default:
insert = function (c) {
return 1;
};
break;
}
switch (typeof prices.remove) {
case 'function':
remove = prices.remove;
break;
case 'number':
remove = function (c) {
return prices.remove;
};
break;
default:
remove = function (c) {
return 1;
};
break;
}
switch (typeof prices.substitute) {
case 'function':
substitute = prices.substitute;
break;
case 'number':
substitute = function (from, to) {
return prices.substitute;
};
break;
default:
substitute = function (from, to) {
return 1;
};
break;
}
switch (typeof prices.transpose) {
case 'function':
transpose = prices.transpose;
break;
case 'number':
transpose = function (backward, forward) {
return prices.transpose;
};
break;
default:
transpose = function (backward, forward) {
return 1;
};
break;
}
function distance(down, across) {
//http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
let ds = [];
if (down === across) {
return 0;
} else {
down = down.split('');
down.unshift(null);
across = across.split('');
across.unshift(null);
down.forEach(function (d, i) {
if (!ds[i]) {
ds[i] = [];
}
across.forEach(function (a, j) {
if (i === 0 && j === 0) {
ds[i][j] = 0;
} else if (i === 0) {
//Empty down (i == 0) -> across[1..j] by inserting
ds[i][j] = ds[i][j - 1] + insert(a);
} else if (j === 0) {
//Down -> empty across (j == 0) by deleting
ds[i][j] = ds[i - 1][j] + remove(d);
} else {
//Find the least costly operation that turns the prefix down[1..i] into the prefix across[1..j] using
//already calculated costs for getting to shorter matches.
ds[i][j] = Math.min(
//Cost of editing down[1..i-1] to across[1..j] plus cost of deleting
//down[i] to get to down[1..i-1].
ds[i - 1][j] + remove(d),
//Cost of editing down[1..i] to across[1..j-1] plus cost of inserting across[j] to get to across[1..j].
ds[i][j - 1] + insert(a),
//Cost of editing down[1..i-1] to across[1..j-1] plus cost of substituting down[i] (d) with across[j]
//(a) to get to across[1..j].
ds[i - 1][j - 1] + (d === a ? 0 : substitute(d, a))
);
//Can we match the last two letters of down with across by transposing them? Cost of getting from
//down[i-2] to across[j-2] plus cost of moving down[i-1] forward and down[i] backward to match
//across[j-1..j].
if (damerau && i > 1 && j > 1 && down[i - 1] === a && d === across[j - 1]) {
ds[i][j] = Math.min(ds[i][j], ds[i - 2][j - 2] + (d === a ? 0 : transpose(d, down[i - 1])));
}
}
});
});
return ds[down.length - 1][across.length - 1];
}
}
return distance;
}
//Returns a distance function to call.
let dl = DamerauLevenshtein();
console.log(dl('12345', '23451'));
console.log(dl('this is a test', 'this is not a test'));
console.log(dl('testing testing 123', 'test'));
I'm sending the number/string 0.001 to a the function below:
SignificantFigures = 4;
function LimitNumberOfDigits(num) {
var tempStr = "";
if (isNaN(num))
return "\xD8";
else{
if (parseFloat(num) === 0 || (num.toString().indexOf('.') === -1 && parseInt(num) < 9999) || num.toString().length <= 4) {
return num;
}
tempStr = parseFloat(num).toPrecision(SignificantFigures);
if (tempStr.indexOf("e") > -1) {
var startE = tempStr.indexOf("e");
var endE = 0;
for (var i = startE +2 ; i < tempStr.length; i++ ) { // + to ignore e and sign (+ or - )
if(parseInt(tempStr[i], 10) > 0) {
endE = i;
}else {
break;
}
}
if (startE + 2 === endE) {
var pow = tempStr[endE];
} else {
var pow = tempStr.substring(startE +2 ,endE);
}
return tempStr.substring(0,startE) + "*10<sup>"+ pow +"</sup>";
}else {
return parseFloat(num).toPrecision(SignificantFigures);
}
}
}
When im sending 0.2 or even 0.11 im getting like 0.2000 and 0.1100.
The issue here is the toPrecision acts like ToFixed.
Ideas?
EDIT
What i want? simple as that, if a numbers needs to be changed e.g 0.012312312041 it should be 0.0123 , numbers like 0.12 or 28 should stay the same.
I'm looking for a way to construct regular expressions to match numeric inputs specified by a given integer range, ie. if I pass in a range of 1,3-4 then a regex would be returned matching just 1, 3 and 4.
I wrote the following method to try and do this:
function generateRegex(values) {
if (values == "*") {
return new RegExp("^[0-9]+$");
} else {
return new RegExp("^[" + values + "]+$");
}
}
I'm having issues however as sometimes I need to match double digits, such as "8-16", and I also need to ensure that if I am passed a single digit value, such as "1", that the generated regex matches only 1, and not say 11.
I really would like this to remain a pretty small snippet of code, but am not sure enough about regexs to know how to do this. Would be massively grateful for any help!
EDIT: I realise I wasn't clear, with my original paragraph, so have edited it. I realise the regex's that I originally generated do not work at all
Regexes don't know anything about numbers, only digits. So [8-16] is invalid because you say match between 8 and 1 (instead of 1 and 8 e.g.) plus the digit 6.
If you want to match numbers, you have to consider them lexically. For example, to match numbers between 1 and 30, you have to write something like (other regexes exist):
/^(30|[1-2]\d|[1-9])$/
I was sure it was 4-8 hours :-) In the end (and in its uselessness) it was a good exercise in composing Regexes. You are free to try it. If we exclude one use of continue and the use of the Array constructor, it's fully jsLint ok.
var BuildRegex = function(matches) {
"use strict";
var splits = matches.split(','),
res = '^(',
i, subSplit, min, max, temp, tempMin;
if (splits.length === 0) {
return new RegExp('^()$');
}
for (i = 0; i < splits.length; i += 1) {
if (splits[i] === '*') {
return new RegExp('^([0-9]+)$');
}
subSplit = splits[i].split('-');
min = BuildRegex.Trim(subSplit[0], '0');
if (min === '') {
return null;
}
if (subSplit.length === 1) {
res += min;
res += '|';
continue;
} else if (subSplit.length > 2) {
return null;
}
max = BuildRegex.Trim(subSplit[1], '0');
if (max === '') {
return null;
}
if (min.length > max.length) {
return null;
}
// For 2-998 we first produce 2-9, then 10-99
temp = BuildRegex.DifferentLength(res, min, max);
tempMin = temp.min;
if (tempMin === null) {
return null;
}
res = temp.res;
// Then here 100-998
res = BuildRegex.SameLength(res, tempMin, max);
}
res = res.substr(0, res.length - 1);
res += ')$';
return new RegExp(res);
};
BuildRegex.Repeat = function(ch, n) {
"use strict";
return new Array(n + 1).join(ch);
};
BuildRegex.Trim = function(str, ch) {
"use strict";
var i = 0;
while (i < str.length && str[i] === ch) {
i += 1;
}
return str.substr(i);
};
BuildRegex.IsOnlyDigit = function(str, start, digit) {
"use strict";
var i;
for (i = start; i < str.length; i += 1) {
if (str[i] !== digit) {
return false;
}
}
return true;
};
BuildRegex.RangeDigit = function(min, max) {
"use strict";
if (min === max) {
return min;
}
return '[' + min + '-' + max + ']';
};
BuildRegex.DifferentLength = function(res, min, max) {
"use strict";
var tempMin = min,
i, tempMax;
for (i = min.length; i < max.length; i += 1) {
tempMax = BuildRegex.Repeat('9', i);
res = BuildRegex.SameLength(res, tempMin, tempMax);
tempMin = '1' + BuildRegex.Repeat('0', i);
}
if (tempMin > tempMax) {
return null;
}
return {
min: tempMin,
res: res
};
};
BuildRegex.SameLength = function(res, min, max) {
"use strict";
var commonPart;
// 100-100
if (min === max) {
res += min;
res += '|';
return res;
}
for (commonPart = 0; commonPart < min.length; commonPart += 1) {
if (min[commonPart] !== max[commonPart]) {
break;
}
}
res = BuildRegex.RecursivelyAddRange(res, min.substr(0, commonPart), min.substr(commonPart), max.substr(commonPart));
return res;
};
BuildRegex.RecursivelyAddRange = function(res, prefix, min, max) {
"use strict";
var only0Min, only9Max, i, middleMin, middleMax;
if (min.length === 1) {
res += prefix;
res += BuildRegex.RangeDigit(min[0], max[0]);
res += '|';
return res;
}
// Check if
only0Min = BuildRegex.IsOnlyDigit(min, 1, '0');
only9Max = BuildRegex.IsOnlyDigit(max, 1, '9');
if (only0Min && only9Max) {
res += prefix;
res += BuildRegex.RangeDigit(min[0], max[0]);
for (i = 1; i < min.length; i += 1) {
res += '[0-9]';
}
res += '|';
return res;
}
middleMin = min;
if (!only0Min) {
res = BuildRegex.RecursivelyAddRange(res, prefix + min[0], min.substr(1), BuildRegex.Repeat('9', min.length - 1));
if (min[0] !== '9') {
middleMin = String.fromCharCode(min.charCodeAt(0) + 1) + BuildRegex.Repeat('0', min.length - 1);
} else {
middleMin = null;
}
}
middleMax = max;
if (!only9Max) {
if (max[0] !== '0') {
middleMax = String.fromCharCode(max.charCodeAt(0) - 1) + BuildRegex.Repeat('9', max.length - 1);
} else {
middleMax = null;
}
}
if (middleMin !== null && middleMax !== null && middleMin[0] <= middleMax[0]) {
res = BuildRegex.RecursivelyAddRange(res, prefix + BuildRegex.RangeDigit(middleMin[0], middleMax[0]), middleMin.substr(1), middleMax.substr(1));
}
if (!only9Max) {
res = BuildRegex.RecursivelyAddRange(res, prefix + max[0], BuildRegex.Repeat('0', max.length - 1), max.substr(1));
}
return res;
};
// ----------------------------------------------------------
var printRegex = function(p) {
"use strict";
document.write(p + ': ' + BuildRegex(p) + '<br>');
};
printRegex('*');
printRegex('1');
printRegex('1,*');
printRegex('1,2,3,4');
printRegex('1,11-88');
printRegex('1,11-88,90-101');
printRegex('1-11111');
printRegex('75-11119');
Test here http://jsfiddle.net/dnqYV/
The C# version is here http://ideone.com/3aEt3E
I'm not sure there is a (sane) way to test integer ranges with RegExp. I believe you're fixated on RegExp, where there are much simpler (more flexible) approaches. Take a look at IntRangeTest().
var range = new IntRangeTest('0,10-20');
console.log(
"0,10-20",
range.test("") == false,
range.test("-5") == false,
range.test("0") == true,
range.test("5") == false,
range.test("11") == true,
range.test("123.23") == false
);
If you feel like it, you can easily add this to Number.prototype. You could also quite easily make this an extension to RegExp, if that's what you're worried about.
Ok so it seems that there are 4 main cases that I need to address:
Single digits, ie 1, would simply generate the regex /^1$/
Multiple digits, ie 12, would require the regex /^12&/
Single digit ranges, ie 3-6, would generate the regex /^[3-6]$/
And finally, multiple digit ranges work in a similar method to multiple digits but with a range, ie 11-14 would become /^1[1-4]$/. These would need to be split into multiple regexes if they span over multiple start digits, Ie 23-31 would become /^2[3-9]|3[0-1]$/
Therefore, all I need to do is identify each of these cases and create a compound regex using | like xanatos suggested. Ie, to match all of the above criteria would generate a regex like:
/^( 1 | 12 | [3-6] | 1[1-4] | 2[3-9]|3[0-1] )$/
Do other agree this seems like a decent way to progress?