/*""" Exercise1_Padding_numbers solution suggestions
Author: jthi
Creation Date: 2024-01-05
Creation JMP Version: JMP Pro 17.2
Description: Figure out how to add padding to numbers using character presentation
in such a way that the numbers are always three characters long. Test with values between
0-999.
Note: Purpose is not to create a function to perform this task. You of course can create
a function or use expressions but we haven't yet covered them in this course.
Examples:
Input Output
1 "001"
10 "010"
100 "100"
Bonus 1:
If the value is less than 0 or over 999 set the value as empty string
Bonus 2:
Figure at least one additional method to perform this same task
Extra:
Perform similar calculation on a data table and create new column
"""*/
//==========================================================
// Input
//==========================================================
Names Default To Here(1);
input_list = {1, 10, 100}; // you can create your own examples
//==========================================================
// Step by step solution
//==========================================================
// Note: All values are between 0-999 (no need to worry about missing value OR values which are 1000 or larger)
// Start in small very simple pieces
// in this step by step solution we make an assumption that the maximum amount of zeros we add is 2
val = 1;
val_str = Char(val); // change into string
res1 = "00" || val_str; // "001" -> OK -> no zeros to remove
val2 = 10;
val_str2 = Char(val2); // change into string
res2 = "00" || val_str2; // "0010" -> NOK -> We must remove ONE zero
val3 = 100;
val_str3 = Char(val3); // change into string
res3 = "00" || val_str3; // "00010" -> NOK -> We must remove TWO zeros
// Create a basic loop to make testing easier
For Each({val}, input_list,
val_str = Char(val);
res = "00" || val_str;
Print(Eval Insert("Input: ¤val¤, Result: ¤res¤", "¤"));
);
// how we can add correct amount of zeros?
// we could base the amount of zeros on the lenght of val_str
// lenght 1 -> add 2
// lenght 2 -> add 1
// length 3 -> add 0
len_val = Length(val_str);
// We could use If, Match or Choose
zeros_to_add = If(len_val == 1,
2
, len_val == 2,
1
, len_val == 3, // could also just use else for this
0
);
zeros_to_add = Match(len_val,
1, 2,
2, 1,
3, 0
);
zeros_to_add = Choose(len_val,
2,
1,
0
);
// or more generic solution
// when length increases by 1 added zeroes decrease by 1 STARTTING from 2
zeros_to_add = 3 - len_val; // min lenght is 1 -> start from addition from 3
// we can test these with loop (next lesson we can turn it into a function to make it even easier)
For Each({val}, input_list,
val_str = Char(val);
zeros_to_add = 3 - Length(val_str);
show(zeros_to_add);
);
// now we know how many zeros to add. How to create them?
// Repeat is good option
val = 1;
val_str = Char(val);
len_val = Length(val_str);
zeros_to_add = 3 - len_val;
zero_str = Repeat("0", zeros_to_add);
// and now we create our final string
val_output = zero_str || val_str;
// test with loop
For Each({val}, input_list,
val_str = Char(val);
len_val = Length(val_str);
zeros_to_add = 3 - len_val;
zero_str = Repeat("0", zeros_to_add);
val_output = zero_str || val_str;
show(val_output);
);
// make into solution (list of strings)
result = {};
For Each({val}, input_list,
val_str = Char(val);
len_val = Length(val_str);
zeros_to_add = 3 - len_val;
zero_str = Repeat("0", zeros_to_add);
val_output = zero_str || val_str;
Insert Into(result, val_output);
);
show(result);
//==========================================================
// Non step by step solutions
//==========================================================
//==========================================================
// Option 1 - Add zeros and use transform each
//==========================================================
input_list = {1, 10, 100};
MAX_STRING_LENGTH = 3;
result = Transform Each({val}, input_list,
val_str = Char(val);
zeros_to_add = MAX_STRING_LENGTH - Length(val_str);
Repeat("0", zeros_to_add) || val_str; // last line will be returned from Transform Each
);
show(result);
//==========================================================
// Option 2 - Remove zeros using Right
//==========================================================
input_list = {1, 10, 100};
// we know that the maximum amount of zeros we can have is 2 -> we can create our string beforehand
MAX_STR_LENGTH = 3;
zero_str = Repeat("0", MAX_STR_LENGTH - 1); // -1 to allow space for our number
result = Transform Each({val}, input_list,
val_str = Char(val);
Right(zero_str || val_str, MAX_STR_LENGTH);
);
show(result);
//==========================================================
// Option 3 - Remove zeros using Substr
//==========================================================
input_list = {1, 10, 100};
MAX_ZERO_STR = "00";
result = Transform Each({val}, input_list,
val_str = Char(val);
res_str = MAX_ZERO_STR || val_str;
start_idx = Length(res_str) - 2;
Substr(res_str, start_idx);
// Substr(res_str, start_idx, Length(res_str));
// Substr(res_str, -3); // should also work
);
show(result);
//==========================================================
// Option 4 - Regex (not really recommended in simple case like this)
//==========================================================
input_list = {1, 10, 100};
MAX_ZERO_STR = "00";
result = Transform Each({val}, input_list,
val_str = Char(val);
res_str = MAX_ZERO_STR || val_str;
Regex(res_str, "\d{3}$"); // take last three numbers
);
show(result);
//==========================================================
// Option 5 - Don't do this
//==========================================================
input_list = {1, 10, 100};
result = Transform Each({val}, input_list,
str = Char(val, 4, 3); // string width is 4 to take decimal separator into account
str_l = Words(str, ".,");
Concat Items(Reverse(str_l), "");
);
show(result);
//==========================================================
// Bonus 1 - Using option 1
//==========================================================
input_list = {1, 10, 100, -1, 1000, 0, ., 99, 10, 999, 9};
MAX_STRING_LENGTH = 3;
result = Transform Each({val}, input_list,
If(!IsMissing(val) & 0 < val < 1000,
val_str = Char(val);
zeros_to_add = MAX_STRING_LENGTH - Length(val_str);
Repeat("0", zeros_to_add) || val_str; // last line will be returned from Transform Each
, // else
"";
);
);
show(result);
//==========================================================
// Bonus 1 (non-working solution) - Debugging script using Try-Catch
//==========================================================
input_list = {1, 10, 100, -1, 1000, 0, .};
MAX_STRING_LENGTH = 3;
result = Transform Each({val}, input_list,
Try(
If(!IsMissing(val) | 0 < val < 1000,
val_str = Char(val);
zeros_to_add = MAX_STRING_LENGTH - Length(val_str);
Repeat("0", zeros_to_add) || val_str; // last line will be returned from Transform Each
, // else
"";
);
,
Show(val, exception_msg); // useful to print the value as then you can test with it
);
);
show(result);
//==========================================================
// Bonus 1 - Adding only valid options to a list and returning list of issues
//==========================================================
// we change into For Each as managing what is returned is much much easier this way
input_list = {1, 10, 100, -1, 1000, 0, .};
MAX_STRING_LENGTH = 3;
result = {};
issue_list = {}; // store list of lists with index and value
aa_issues = Associative Array(); // other option (use idx as key and value as value)
For Each({val, idx}, input_list,
Try(
If(!IsMissing(val) & 0 < val < 1000,
val_str = Char(val);
zeros_to_add = MAX_STRING_LENGTH - Length(val_str);
res = Repeat("0", zeros_to_add) || val_str; // last line will be returned from Transform Each
Insert Into(result, res);
, // else
Insert Into(issue_list, Eval List({Eval List({idx, val})}));
aa_issues[idx] = val; // other option
);
, // catch
Show(val, exception_msg);
);
);
show(result, issue_list, aa_issues);
//==========================================================
// Extra, create a formula to perform similar action
//==========================================================
dt_input = New Table("Exercise1_Padding_Solution",
Add Rows(1000),
Compress File When Saved(1),
New Column("Input", Numeric, "Continuous", Set Values(0::999))
);
//==========================================================
// Using simple formula with hard-coded values
//==========================================================
dt_input << New Column("Solution1", Character, Nominal, Formula(
Right("00" || Char(:Input), 3);
));
//==========================================================
// Using Local() and variables
//==========================================================
dt_input << New Column("Solution2", Character, Nominal, Formula(
Local({
MAX_STR_LENGTH = 3,
zero_str = Repeat("0", MAX_STR_LENGTH - 1)
},
Right(zero_str || Char(:Input), MAX_STR_LENGTH);
);
));
//==========================================================
// Using As Constant()
//==========================================================
// variables should be evaluated only on first row when using this
dt_input << New Column("Solution3", Character, Nominal, Formula(
As Constant(
MAX_STR_LENGTH = 3;
zero_str = Repeat("0", MAX_STR_LENGTH - 1);
);
Right(zero_str || Char(:Input), MAX_STR_LENGTH);
));
//==========================================================
// Using table variable
//==========================================================
dt_input << New Table Variable("MAX_INPUT_LENGTH", 3);
// Table variables are stored as strings so I would convert them just to be sure
// dt_input << Get Table Variable("MAX_INPUT_LENGTH");
dt_input << New Column("Solution4", Character, Nominal, Formula(
Right(Repeat("0", Num(:MAX_INPUT_LENGTH) - 1) || Char(:Input), Num(:MAX_INPUT_LENGTH));
));
// Note, to make sure formulas have been evaluated use dt_ref << Run Formulas; NOT wait(0);
// Note, when using formulas it might be a good idea to either remove them OR suppress their evaluation
// if there is no need for the values to update after initial creation
// col_ref << Delete Formula;
// col_ref << Suppress Eval(1);
//==========================================================
// Using For Each Row instead of formula
//==========================================================
// if you can be sure about the column name
dt_input << New Column("Solution5", Character, Nominal);
For Each Row(dt_input,
:Solution5 = Right("00" || Char(:Input), 3);
);
// if you aren't you can use column reference
new_col = dt_input << New Column("Solution5.1", Character, Nominal);
For Each Row(dt_input,
new_col[Row()] = Right("00" || Char(:Input), 3);
// could also use :Solution5
);
// or with column name
new_col = dt_input << New Column("Solution5.2", Character, Nominal);
For Each Row(dt_input,
As Column(dt_input, (new_col << get name)) = Right("00" || Char(:Input), 3);
);
// or with column name
new_col = dt_input << New Column("Solution5.3", Character, Nominal);
For Each Row(dt_input,
Column(dt_input, (new_col << get name))[] = Right("00" || Char(:Input), 3);
);
// note how [] and [Row()] are being used (they are same thing but [Row()] is more explicit)
//==========================================================
// Using << Set Each Value (THIS IS NOT INTENDED BEHAVIOUR SO THIS MIGHT CHANGE)
//
https://community.jmp.com/t5/JMP-Wish-List/Make-using-formula-expressions-in-Set-Each-Value-and-using/idi-p/666966
//==========================================================
dt_input << New Column("Solution6", Character, Nominal, << Set Each Value(
Right("00" || Char(:Input), 3);
));
Write();