replacing letters in text (pseudo-code) - pseudocode

I'm making a script to create a username. It should be four letters long; traditionally we've used 3 letters of the last name + 1 of the first name.
If it was already used we manually thought of an alternative.
So if my name is Fred Flinstones we should try FLIF. If this doesnt work; we loop through the name: FLIA, FLIB, FLIC ... FLIZ, FLAA, FLAB, FLAC, ... FLZZ, FAAA, FAAB, ...
The easiest way is to loop through last letters; then make another set of loops through second last letter and loop through last letters; then a set of loops through third last, second last, last; and fourth+third+second+last.
This makes a lot of do while loops nested in eachother + unreadable for other humans + a lot of typing.
I could use a counter per letter but that also doesn't seem elegant
I could try with one counter and then using mod 26 to see how many letters need replacement (but that seems very complex).
Is there some elegant/efficient ways to do this?
Bonus points for first trying to keep the string as 'logically correct' as possible (f.e. keeping the last letter an F for Fred or skipping letters FLIF; FLNF, FLSF, FLTF, ...) .

Not sure if this is what you mean, but if you structure your username-script in the following way (I used PHP as language), you can extend it by adding options with higher fuzz factors while keeping the code readable:
echo findName('FLINTSTONE', 'FRED');
function findName($last, $first) {
for ($fuzzFactor = 0; ; $fuzzFactor++) {
$candidates = fuzzNames($last, $first, $fuzzFactor);
if (empty($candidates)) {
// exhausted
return "sorry, I'm out of options!";
}
foreach ($candidates as $candidate) {
if (isUnique($candidate)) {
return $candidate;
}
}
}
}
function fuzzNames($last, $first, $fuzzFactor) {
switch ($fuzzFactor) {
case 0:
// no fuzz, return first choice
return array(substr($last, 0, 3) . $first[0]);
case 1:
// replace the third letter of the last name
// by the fourth/fifth/.../last letter (FLNF, FLTF, ... , FLEF)
$candidates = array();
for ($i = 3; $i < strlen($last); $i++) {
$candidates[] = substr($last, 0, 2) . $last[$i] . $first[0];
}
return $candidates;
case 2:
// replace the second and third letter of the last name
// by their follow-ups (FINF, FITF, ... , FNEF)
$candidates = array();
for ($i = 2; $i < strlen($last) - 1; $i++) {
for ($j = $i + 1; $j < strlen($last); $j++) {
$candidates[] = $last[0] . $last[$i] . $last[$j] . $first[0];
}
}
return $candidates;
default:
return array();
}
}

Related

Appropriate way to return an arrayref from a sub with optional sorting in Perl version 5.20

I try to write a subroutine under Perl 5 version 5.20, that creates a large directory list stored in an array. The subroutine returns the result as an arrayref. For convenience reasons I want the have the option to sort the result.
#!/usr/bin/env perl
use v5.20;
use warnings;
use strict;
use File::Slurp qw(read_dir);
use Time::HiRes;
use feature qw(signatures);
no warnings 'once';
no warnings 'experimental';
no warnings 'experimental::signatures';
my $PATH='/net/dbfs/GRM-RS/Flight-Campaigns/2021-08-23.Ram-Head-i-22.SE-01/cam/MM010259/iiq/';
sub fsReadDir($base, $sort, $mode = 1) {
$base //= '.'; # Base path default is the current path
$sort //= 0; # Flag for array sorting of the result
my #res=read_dir($base);
if ($sort) {
return [sort(#res)] if $mode == 1;
if ($mode == 2) {
#res = sort(#res);
return \#res;
}
} else {
return \#res;
}
}
sub testSorting($sort, $mode, $max = 1000) {
my $start = [Time::HiRes::gettimeofday()];
my $count = 0;
for my $ix (0..$max) {
my $array = fsReadDir($PATH, $sort, $mode );
$count = #$array;
}
my $end = time();
my $dif = Time::HiRes::tv_interval($start);
print "SORT: $sort MODE: $mode COUNT: $count TIME: $dif s\n"
}
testSorting(0, 1);
testSorting(1, 1);
testSorting(1, 2);
Results
/usr/bin/env perl "test-array.pl"
SORT: 0 MODE: 1 COUNT: 14861 TIME: 6.882694 s
SORT: 1 MODE: 1 COUNT: 14861 TIME: 9.131504 s
SORT: 1 MODE: 2 COUNT: 14861 TIME: 8.622628 s
What is the effective way to sort the array directly at the return level?
If you insist on sorting out the sorting business in the return statement itself can use a ternary
return $sort ? [ sort #res ] : \#res;
This may be all well and clear enough in simple cases.
However, I find it clearer to first deal with cases and options and then return the result
#res = sort #res if $sort;
if ($mode == 1) { ... } # modes given in the question do nearly the same,
elsif ($mode == 2) { ... } # but imagine different processing based on value
...
return \#res;
Also, sorting in place should be a little more efficient.
If this were about efficiency then you'd want to benchmark different approaches, and under realistic circumstances. For one, it may all get blown out of the water by reading a large directory, when one may not be able to tell any performance difference in how exactly the return is constructed.
So I'd go for clarity, until it is clearly seen that the choice does affect performance.

Scalar value being affected after push, or not... (Raku)

I have difficulty understanding when and why the value held by a pushed Scalar container is affected after the push. I'll try to illustrate the issue that I ran into in a more complicated context in two stylized examples.
*Example 1 * In the first example, a scalar $i is pushed onto an array #b as part of a List. After the push, the value held by the scalar is explicitly updated in later iterations of the for loop using the $i++ instruction. These updates have an effect on the value in the array #b: at the end of the for loop, #b[0;0] is equal to 3, and no longer to 2.
my #b;
my $i=0;
for 1..3 -> $x {
$i++;
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $x == 2 {
#b.push(($i,1));
say 'Pushed $i : ', #b[0;0].VAR.WHICH, " ", #b[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", #b;
say 'Pushed $i : ', #b[0;0].VAR.WHICH, " ", #b[0;0].VAR.WHERE;
Output example 1:
Loose var $i: Scalar|94884317665520 139900170768608
Loose var $i: Scalar|94884317665520 139900170768648
Pushed $i : Scalar|94884317665520 139900170768648
Loose var $i: Scalar|94884317665520 139900170768688
Post for-loop
Array : [(3 1)]
Pushed $i : Scalar|94884317665520 139900170768688
* Example 2 * In the second example, the scalar $i is the loop variable. Even though $i is updated after it has been pushed (now implicitly rather than explicitly), the value of $i in array #c does not
change after the push; i.e. after the for loop, it is still 2, not 3.
my #c;
for 1..3 -> $i {
say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
if $i == 2 {
#c.push(($i,1));
say 'Pushed $i : ', #c[0;0].VAR.WHICH, " ", #c[0;0].VAR.WHERE;
}
}
say "Post for-loop";
say "Array : ", #c;
say 'Pushed $i : ', #c[0;0].VAR.WHICH, " ", #c[0;0].VAR.WHERE;;
Output example 2:
Loose var $i: Scalar|94289037186864 139683885277408
Loose var $i: Scalar|94289037186864 139683885277448
Pushed $i : Scalar|94289037186864 139683885277448
Loose var $i: Scalar|94289037186864 139683885277488
Post for-loop
Array : [(2 1)]
Pushed $i : Scalar|94289037186864 139683885277448
Question: Why is $i in #b in example 1 updated after the push, while $i in #c in example 2 is not?
edit:
Following #timotimo's comment, I included the output of .WHERE in the examples. This shows the (WHICH/logical) scalar-identity of $i stays the same, while its memory address changes through the various loop iterations. But it does not explain why in example 2 the pushed scalar remains tied to the same WHICH-identity in combination with an old address ("448).
A scalar value is just a container. You can think of them as a kind of smart pointer, rather than a primitive value.
If you do an assignment
$foo = "something"; #or
$bar++;
you are changing the scalars value, the container stays the same.
Consider
my #b;
my $i=0;
for 1..5 -> $x {
$i++;
#b.push(($i<>,1)); # decontainerize $i and use the bare value
}
say #b;
and
my #b;
my $i=0;
for 1..5 -> $x {
$i := $i + 1; # replaces the container with value / change value
#b.push(($i,1));
}
say #b;
Both of which work as expected. But: In both cases, the thing in the list is not mutable anymore, because there is no container.
#b[4;0] = 99;
will therefore die. So just use the loop variable then, right?
No.
for 1..5 -> $x {
#b.push(($x,1)); #
}
#b[4;0] = 99; #dies
even if we iterate over a list of mutable things.
my $one = 1;
my $two = 2;
my $three = 3;
my $four = 4;
my $five = 5;
for ($one, $two, $three, $four, $five) -> $x {
#b.push(($x,1));
}
#b[4;0] = 99; #dies
So there is no aliasing happening here, instead the loop variable is always the same container and gets values assigned that come from the other containers.
We can do this though.
for ($one, $two, $three, $four, $five) <-> $x {
#b.push(($x,1));
}
#b[4;0] = 99; # works
for ($one, $two, $three, $four, $five) -> $x is rw {
#b.push(($x,1));
}
#b[4;0] = 99; # works too
A way to make "the thing" mutable is using an intermediate variable.
for 1..5 -> $x {
my $j = $x;
#b.push(($j,1)); # a new container
}
#b[4;0] = 99;
works fine. Or shorter and more in the original context
my #b;
my $i=0;
for 1..5 -> $x {
$i++;
#b.push((my $ = $i, 1)); # a new anonymous container
}
#b[4;0] = 99;
say #b; # [(1 1) (2 1) (3 1) (4 1) (99 1)]
See also:
https://perl6advent.wordpress.com/2017/12/02/#theoneandonly
https://docs.perl6.org/language/containers
After playing with and thinking about my above question for some time, I'll wager an answer... It's pure conjecture on my part, so please feel free to say it's non-sense if it is, and if you happen to know, why...
In the first example, $i is defined outside of the lexical scope of the for loop. Consequently, $i exists independent of the loop and its iterations. When $i is referenced from inside the loop, there is only one $i that can be affected. It is this $i that gets pushed into #b, and has its contents modified afterwards in the loop.
In the second example, $i is defined inside the lexical scope of the for loop. As #timotimo pointed out, the pointed block get's called for each iteration, like a subroutine; $i is therefore freshly declared for each iteration, and scoped to the respective block. When $i is referenced inside the loop, the reference is to the block-iteration-specific $i, which would normally cease to exist when the respective loop iteration ends. But because at some point $i is pushed to #c, the reference to the block-iteration-specific $i holding value 2 cannot be deleted by the garbage collector after termination of the iteration. It will stay in existence..., but still be different from $i in later iterations.

What makes this a fixed-length list in Dart?

List<String> checkLength(List<String> input) {
if (input.length > 6) {
var tempOutput = input;
while (tempOutput.length > 6) {
var difference = (tempOutput.length/6).round() + 1;
for (int i = 0; i < tempOutput.length - 1; i + difference) {
tempOutput.removeAt(i); //Removing the value from the list
}
}
return tempOutput; //Return Updated list
} else {
return input;
}
}
I am trying to delete something out of a temporary list. Why does it not work? I do not see how it is fixed, in other problems I have solved, I used a similar approach and it worked (Even identical nearly)
Please note I am kind of new to Dart, so please forgive me this sort of question, but I couldn't figure out the solution.
Find the Code available in the Dart Link
Code in Dart
You can ensure that tempOutput is not a fixed-length list by initializing it as
var tempOutput = new List<String>.from(input);
thereby declaring tempOutput to be a mutable copy of input.
FYI it also looks like you have another bug in your program since you are doing i + difference in your for-loop update step but I think you want i += difference.
Can you please try this code and let me know is that works?
List<String> checkLength(List<String> input) {
if (input.length > 6) {
var tempOutput = input;
while (tempOutput.length > 6) {
var difference = (tempOutput.length/6).round() + 1;
for (int i = 0; i < tempOutput.length - 1; i = i + difference) {
tempOutput.removeAt(i); //Removing the value from the list
}
}
return tempOutput.toList(); //Return Updated list
} else {
return input.toList();
}
}
Note: You used "i + difference" which is same value say for example in first iteration you i=1 and difference = 1, then "tempOutput.removeAt(i)" will remove the value at "1" position, again in the second iteration you are trying to remove the same position, so the error clearly states "Cannot remove from the Fixed length"
Here the i value has to be incremented or decremented for each iteration process, in your for loop that is missing.
The answer of #harry-terkelsen was very helpful for solving the fixed-length problem.
For those who were asking about my algorithm:
The difference is for skipping the amount of characters when wanting to remove some. Also, I had to change the for-loop, as it did not quite do what I wanted it to.
The fix is here! https://github.com/luki/wordtocolor/blob/master/web/algorithms.dart
Thank you for understanding me!

(PHP) Probability of two random strings be same

I have this code for generating random strings
public function random_string($length = 5)
{
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
return substr(str_shuffle($chars),0,$length);
}
So, is it possible that two generated strings can be same ?
In my case, there can be a maximum of 62P5 (using permutation) numbers of strings of 5 characters.
But whats the possibility that the 10th & 1000th generated random strings be same ?
This is known as the birthday problem and can be solved by
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
$length = 5;
$numChars = strlen($chars);
$numberOfStringsGenerated = 50000;
print "numStringsGenerated: " . $numberOfStringsGenerated . "\n";
print "numChars: " . $numChars . "\n";
print "lengthOfString: " . $length . "\n";
$totalPerms = 1;
for ($ii=0; $ii<$length; $ii++) {
$totalPerms *= $numChars - $ii;
}
print "totalPerms: " . $totalPerms . "\n";
$totalProbablity = 1;
for ($ii=0; $ii< $numberOfStringsGenerated; $ii++) {
$totalProbablity *= ($totalPerms - $ii)/$totalPerms;
}
print "Probablity: ";
print 1 - $totalProbablity . "\n";
Here is the codepad output
Here is the Wikipedia page
This calculation assumes that the PRNG for the str_shuffle is good enough for all permutations to be equally likely, which won't be exactly true, especially as the number of chars increases.
Obviously that is possible.
The right way to do this, is store already used strings in a database.
I use this in a system that generates a random session token that is stored at database.
Always that I generate a new random session token, i query for it in session table. If no results, OK, else, generate a new token.
The probability is very low, but not impossible, and everytime you insert new tokens at table, the probability of overwriting just grow.

Converting an if code into forloop statement

Right now i have to write a code that will print out "*" for each collectedDots, however if it doesn't collect any collectedDots==0 then it print out "". Using too many if statements look messy and i was wandering how you would implement the forloop in this case.
As a general principle the kind of rearrangement you've done here is good. You have found a way to express the rule in a general way rather than as a sequence of special cases. This is much easier to reason about and to check, and it's obviously extensible to cases where you have more than 3 dots.
You probably have made an error in confusing your target number and the iteration value, I assume that collectedDots contains the number of dots you have (as per your if statement) and so you need to introduce a variable to count up to that value
for (int i =0; i <= collectedDots; i++)
{
stars = "*";
System.out.print(stars);
}
Ok, so you already have a variable called collectedDots that is a number which tells you how many stars to print?
So your loop would be something like
for every collected dot
print *
But you can't just print it out, you need to return a string that will be printed out. So it's more like
for every collected dot
add a * to our string
return the string
They key difference between this and your attempt so far is that you were assigning a star to be your string each time through the loop, then at the end of it, you return that string–no matter how many times you assign a star to the string, the string will always just be one star.
You also need a separate variable to keep track of your loop, this should do the trick:
String stars = "";
for(int i = 0; i < collectedDots; i++)
{
stars = stars + "*";
}
return stars;
You are almost correct. Just need to change range limit of looping. Looping initial value is set to 1. So whenever you have collectedDots = 0, it will not go in loop and will return "", as stars is intialized with "" before loop.
String stars = "";
for (int i =1; i <= collectedDots; i++)
{
stars = "*";
System.out.print(stars);
}
return stars;

Resources