### Write a simple but impactful script

#### Florian Rohrer on May 24, 2018

Basic challenge (simple): Write a script that produces all possible 4-digit numbers (0000...9999), then put them into a random order and save the... [Read Full]

Bash:

`for i in {0..9999}; do printf "%04d\n" \$i; done | sort -R > pins.txt`

Using `shuf` utility for shuffling:

`for i in {0..9999}; do printf "%.4d\n" \$i; done | shuf > pins.txt`

The two scripts are equivalent as the `man sort` page tells that `-R` option uses `shuf`.

I don't have `sort -R` or `shuf` (I'm on OS X). I did not know you could do the dot precision thing with integers! My solution was basically the same, but I did `"%04d\n"`

You can get `gshuf` if you install the GNU `coreutils` through homebrew or ports.

Ahh, there we go _^

Shorter: `seq -w 9999 | shuf > pins.txt`

Just wanted to share my script :p

``````
Array.from(Array(1001).keys())
.sort(number => number - Math.random() * number * 2);

``````

Only gets all the numbers from 0000 to 0999.

edit: Simple fix though I think - should say Array(10000) not Array(1000)

Hey good catch, thanks.

Comment marked as low quality/non-constructive by the community View code of conduct

Hey, this is nice. Can you please explain the function you passed to `sort()`?

Sure, we were supposed to sort randomly and `sort()` expects a function that compares two values and returns `>0` if greater `0` if equal and `<0` if lesser, so,

• For the random order, I used `Math.random` that returns a value between 0 and 1

• To be sure that it can return a negative number I multiplied the random times `number * 2` so:

• If `Math.random < 0.5` it will be positive
• If `Math.random == 0.5` it will be zero
• If `Math.random > 0.5` it will be negative

However, since we have three possible cases it could be better to do something like:

``````
.sort(number => number - Math.floor(Math.random() * number * 3));

``````

That way there is a 33.33% of probability for each case.

I hope you don't mind me answering on Pichardo's behalf (or Pichardo).

Sort iterates over consecutive pairs through the array and takes their differences. If a negative value returns, it knows the previous value comes before it, if positive, then after, and it sorts the array accordingly. But we don't want that to happen here as we're dealing with strings, e.g. we don't want the string, "39" to come after the string, "220" but alphabetically, they ought to just like "alphabet" comes before "bat". Since sort only knows what to do based on the sign it receives, if we pass the two indices as parameters to a function and have it do their difference numerically, it sorts everything as expected. And since we don't actually want a sort in this case, but want things random, if we only pass the first of the two indices of each pair and compare it to a random value, we get things randomly "sorted".

An even simpler way to achieve the same result would be to just do .sort(number=>.5 - Math.random()).

That's right `0.5 - Math.random()` would've worked as well

What about an OO version of the possible solution in Ruby?

``````# https://dev.to/r0f1/write-a-simple-but-impactful-script-7ba
# Write a script that produces all possible 4-digit numbers (0000...9999),
# then put them into a random order and
# save the output into a text file

class ExcerciseOrquestrator

def initialize(output_file_name)
@output_file_name = output_file_name
end

def process(digits)
output = NumberGenerator.new(digits).process
write_to_file(output)
end
private

def write_to_file(output)
open_file do |file|
output.each do |row|
file.write("#{row}\n")
end
end
end

def open_file
File.open(output_file_name, 'w') do |file|
yield(file)
end
end
end

class NumberGenerator

def initialize(digits)
@digits = digits
end

def max_number
(10 ** digits) -1
end

def first_number
0
end

def process
arr = do_generate
(arr || []).shuffle
end

private

def do_generate
(first_number..max_number).each_with_object([]) do |digit, acc|
acc << digit.to_s.rjust(digits, '0')
end
end
end

ExcerciseOrquestrator.new('randon_numbers').process(4)
``````

Hi, Victor! 😊

I'm super ambivalent about this, lol! On one hand, I think the right solution for the problem is the procedural one-liner `File.write "leaked_pins.txt", (0..9999).map { |n| "%04d\n" % n }.shuffle.join`, but on the other hand, I think it's incredibly important to be able to do what you're doing here.

So, since you took the time to write it, I'll take the time to review and refactor it. Hopefully I can be helpful 😊 Also, not everyone is going to agree with me, so I'll try to offer my reasoning for each opinion. My refactored code is here.

• It writes to the wrong filename. I'm only pointing that out b/c if we're making a solution like this, then we're imagining ourselves in a professional-like environment, where the original question is a stand-in for a much more sophisticated real-world problem. In that kind of environment, it's important to be attentive to requirements. Note that, at work, if someone gave me the exact problem that the OP gave, I would write the one-liner. The reason to go with a solution like yours isn't whether you're at work or not, it's that real-world requirements and use-cases tend to be more sophisticated, so as those come in, my one-liner will need to evolve in the direction of what you've written.
• Life will be better when your objects behave like functions (because you won't have to worry about the state of the object going wonky across invocations). A function takes arguments and returns a result, so in this case, I would move all arguments to the constructor (handles the input part), and then the calculation and output to `#process`. So now we would call it like this: `ExcerciseOrquestrator.new('leaked_pins.txt', 4).process`. A natural evolution from that point is `ExcerciseOrquestrator.process('leaked_pins.txt', 4)`, which allows you to abstract the implementation to the point that callers don't even need to know whether an object is created to process the task or not.
• In Ruby, the "do that thing you do" method is `#call`, rather than `#process`
• It's best to avoid exposing anything you don't need to expose, so on `ExcerciseOrquestrator`, I'd move the reader into the private section, and on `NumberGenerator`, I'd move `#digits`, `#max_number`, and `#first_number` into the private section. Treat them as implementation details until there is a need to expose them (and even then, question the need before you oblige it).
• Once you move `attr_reader :output_file_name` into the private section, you can turn it into an `attr_accessor` Presumably the reason you did reader over accessor is because you don't want anyone to be able to call the setter from the outside, which is a good intuition, making it private accomplishes the same thing. Once you have the `attr_accessor`, you can change the `@output_file_name = ...` to `self.output_file_name = ...`, the advantage of this is that it will explode helpfully if they ever get out of alignment. Eg if you're refactoring you might change the name, if you forget to change it where you set the value, then it will just set the wrong ivar, but if you use the setter, you'll get a helpful `NoMethodError`.
• `file.write("#{row}\n")` can become `file.puts row`, and since `puts` will take an array of things to puts, you can remove the iteration `open_file { |file| file.puts output }`
• `#write_to_file` takes an argument named `output`, which I would expect to be a string, given the name and the responsibilities of this class. A better name might be `pins`, `numbers`, `rows`, `elements`, or `lines`, which makes it clearer that it's a collection. In your example, you call each element a `row`, so renaming `output` to `rows` is a pretty reasonable choice. Generally, I'd start with `pins` or `pin_numbers`, because it's the most concrete, so it's the easiest to understand, and then I'd move to something more abstract, as the class becomes more abstract (ie as the numbers aren't always pins, or as the things to write aren't always numbers).
• I don't see the point of `do` on `do_generate`
• `do_generate` always returns a list, so no need for `(arr || [])`, and thus no need for the lvar, now `NumberGenerator#process` can be implemented as `do_generate.shuffle`
• In `#do_generate`, use `map` rather than `each_with_object`, eg `(first_number..max_number).map { |digit| digit.to_s.rjust(digits, '0') }`
• I might rename `#max_number` to `#last_number`, just to to align it with `#first_number`
• In `#do_generate`, the element is named `digit`, but that implies it's 0-9, I'd rename this to `n` or `number` (`n` is totally fine here, even `i` would be okay, partly because it's incredibly common to use those names for this kind of thing, so people understand it, and partly because we're iterating over `first_number..max_number`, so clearly it's a number)
• In `NumberGenerator`, the word `digits` could imply a collection of digits to generate from, so I'd rename it to `num_digits` to make it clear that we're expecting an int.
• In `#open_file`, it passes a block which then yields to the method's block. So, it's just sort of passing the argument through. We can instead explicitly receive the block `def open_file(&block)` and then pass that, rather than our own block literal: `File.open(output_file_name, 'w', &block)`
• In `#max_number`, be careful to put matching whitespace on both sides of operators. Here, it's not an issue, but in other situations it can be read as "negative one", which can change how it parses. Example: `[10, 20, 30].first + 1 # => 11` vs `[10, 20, 30].first +1 # => [10]`
• Randomness is a pretty big dependency, so consider injecting it.
• If the OP was more real-world, we could rename the class to be something meaningful, and then I would probably use keyword arguments instead of ordinal ones.

Hi Josh!
I have to say, I was really impressed about the time you took to get all those comments together.
It really helps me, it really helps the community reading this comments.

1. `it writes to the wrong filename.` That's quite not 100% accurate, as the original excersice (without the bonus) tells: "Then put them into a random order and save the output into a text file." .. as you can see, no file specified.

2. Agree

3. Agree! (and consider it a mental note tattooed to my forehead!)

4. Agree as well, I guess I had the intention to move those two methods down the private section, but never did. Clumsy Victor!

5. `attr_reader` vs `attr_accessor`.. I have always liked the idea to have inmutable objects rather than allowing a change outside of the Object itself. It doesn't feel right. So, unless there's an explicit need to change the object and do recalculation, I'd stick with `attr_reader`

6. `do_generage` "There are only two hard things in Computer Science: cache invalidation and naming things". -- Phil Karlton

7. Agree

8. Agree

9. Agree
...

Overall, I really liked your approach.
One thing I could eventually do better, is follow Ruby style guide github.com/bbatsov/ruby-style-guide like single line method definitions, or somethimes using parenthesis and some other times not.

On any case, Thank you Josh! Thank you for your time and for your refactor.

`it writes to the wrong filename.` That's quite not 100% accurate, as the original excersice (without the bonus) tells: "Then put them into a random order and save the output into a text file." .. as you can see, no file specified.

Ahh, yes, this is fair. The filename was part of the "bonus challenge", which hopefully no one actually did :P

`attr_reader vs attr_accessor..` I have always liked the idea to have inmutable objects rather than allowing a change outside of the Object itself. It doesn't feel right. So, unless there's an explicit need to change the object and do recalculation, I'd stick with attr_reader

Yeah, I'm wary of mutability, too (hence moving the arg from `process` to `initialize`). The purpose for the `accessor` here is so that when we initialize it, we can do `self.var = ...` rather than `@var = ...`, which I prefer because if the names become misaligned, then it will error where we try to set it, rather than where we do something after accessing it (or worse, if it doesn't error at that point, b/c `nil` is a valid value, and instead it blows up elsewhere in the program, or we just get really unexpected results). If we were calling the setter more than once, I'd advocate using a local var instead of an instance var. I guess I'm thinking of it as a "one-time-use" setter.

You know, the more I write Ruby, the more I contemplate making my own `attr_*` methods :P In this case, the way I use it, a better definition would be something like this.

One thing I could eventually do better, is follow Ruby style guide github.com/bbatsov/ruby-style-guide like single line method definitions, or somethimes using parenthesis and some other times not.

I had no issue with any of your syntactic choices (other than the `-1` having mismatched whitespace). Looking at mine, there were a few weird ones, I think that's b/c I was inlining things so that my code samples in the comments would be inline, because the markdown processor doesn't seem to nest code blocks inside of lists. But, I initially wrote all my methods as multiline, and it was really just an error from trying to juggle the formatting requirements of the different places the data existed (my editor, the gist, within the comments).

I'm going to need to see the full test suite for this too 😉

Serious question - How do you test randomness of an output?

One way is by controlling the seeder if possible, seeding it with same value every time should give you the same value every time.

There are some languages where you can instruct the test suite to run a test e.g. a hundred times and if those don't break the code you can be fairly confident (though not sure) that the code does what's intended. If your code takes input these tests usually test boundary conditions, maybe max and min values and a number of random values. If I remember correctly I saw it when playing around with Haskell.

I'd check the things you can know. Such as, if you ran the same method twice then it should result in two arrays of the same size that contain all the same things, but that aren't equal, i.e. the order is different.

I tried another thing recently where I needed to create a random string as output. I used dependency injection for the randomiser function with a default to the built in language version. Then in my test, I used a deterministic object for the randomiser function, such that I knew what the output was. I wasn't implementing the actual randomiser function, so testing it is not necessary, but testing that I'd call the right method on it and it returned the thing I expected satisfied me at the time.

Just some ideas.

i.e. the order is different.

But wouldn't this fail at times?

f.e. I have 3 elements in my array, `[1, 2, 3]`. Now the shuffle method only has six outcomes here, so there is a real possibility that the tests might randomly fail even if the code is correct.

Dependency injection seems like a better approach if you want to test it, but it makes code not as nice to read.

Aye, that's true. I was kind of thinking about it in terms of generating an array of 10000 items!

Writing testable code is a trade off, but probably worthwhile in the long run. Dependency injection itself makes for more and more flexible code without a great deal of extra cognitive overload, so I am a big fan of it at the moment.

This was a great talk from Sandy Metz that drove towards this point for a different reason too. I recommend a watch!

Sharing my Ruby version of this script. Feel free to use to attempt the bonus challenge!

``````File.open("leaked_pins.txt", "w") do |file|
(0...10000).to_a.shuffle.each do |number|
file << number.to_s.rjust(4, "0") + "\n"
end
end
``````

That's with T-SQL using a Tally table

``````WITH
L0   AS(SELECT 1 AS C UNION ALL SELECT 1 AS O),         -- 2 rows
L1   AS(SELECT 1 AS C FROM L0 AS A CROSS JOIN L0 AS B), -- 4 rows
L2   AS(SELECT 1 AS C FROM L1 AS A CROSS JOIN L1 AS B), -- 16 rows
L3   AS(SELECT 1 AS C FROM L2 AS A CROSS JOIN L2 AS B), -- 256 rows
L4   AS(SELECT 1 AS C FROM L3 AS A CROSS JOIN L3 AS B), -- 65,536 rows
Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS N FROM L4),
Ord  AS(SELECT TOP 10000 N - 1 AS N FROM Nums ORDER BY N)

SELECT FORMATMESSAGE('%04i', CAST(N AS INT)) AS N
FROM Ord
ORDER BY NEWID();
``````

I'll see you and raise you Postgres :)

``````SELECT n1.v, n2.v, n3.v, n4.v
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) n1 (v)
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) n2 (v)
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) n3 (v)
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) n4 (v)
ORDER BY random();
``````

Works like a charm in MSSQL if `random()` replaced with `newid()`! :)

Here's my python approach:

``````from random import sample
with open('leaked_pins.txt', 'w') as f:
[f.write('%04d\n'%i) for i in sample(range(0, 10000), k=10000)]
``````

That is awesome. Didn't know you could use an `f.write()` inside a list comprehension :D Real nice.

I didn't know this for a long time, but you can use strings to build ranges in Ruby as well, avoiding the need for any fancy padding with zeros!

``````pins = ("0000".."9999").to_a.shuffle.join("\n")
File.open("pins.txt", "w") { |f| f << pins }
``````

PowerShell

``````0..9999 | % { \$_ -f 'D4' } | sort { Get-Random } > leaked_pins.txt

Send-MailMessage `
-From 'me@fabrikam.com' `
-To 'coworker@fabrikam.com' `
-Subject 'These PIN numbers have been leaked' `
-Body 'You should check whether your pin is in the file or not.' `
-Attachments 'leaked_pins.txt' `
-SmtpServer 'smtp.fabrikam.com'
``````

Clojure?

`````` (spit "./hacks.txt"
(clojure.string/join "\n"
(shuffle
(map
#(format "%04d" %)
(range 0 10000)))))
``````

F#

``````do
let rnd = System.Random()
use file = System.IO.File.CreateText("leaked_pins.txt")

[0..9999]
|> Seq.sortBy (fun _ -> rnd.Next())
|> Seq.iter (fprintfn file "%04d")
``````

``````# python 3.6+
import sys, random

def usage(exit_code=0):
print('usage: python3 rand9999.py [FILE]')
sys.exit(exit_code)

if '-h' in sys.argv or '--help' in sys.argv:
usage()

if len(sys.argv) > 2:
usage(1)

filename = None
if len(sys.argv) == 2:
filename = sys.argv[1]

# Feel free to reply if you can think of a cleaner way to do this.
# Putting 'f = open(..) if.. else..' outside the 'with',
# and then doing "with f as file:" makes it more readable,
# but also seems unsafe, as it could lead to forgetting to
# close files as a general practice.
with (open(filename, 'w') if filename else sys.stdout) as file:
numbers = list(range(10000))
random.shuffle(numbers)
for num in numbers:
file.write(f'{num:#04d}\n')
``````

It would have been cleaner to use random.sample like @alonsovb did.

Edit2: I made a post about some different ways to do the `file_or_stdout` thing. Maybe you can think of a better way.

``````<?php
foreach (\$numbers = range(0, 9999) as &\$number) {
}
shuffle(\$numbers);
file_put_contents('leaked_pins.txt', \$numbers);
``````

Here's my attempt using Go:
(Keep in mind that I've only been introduced to Go a few days ago so I have absolutely no idea what I'm doing, feel free to improve this)

``````package main

import(
"bufio"
"os"
"fmt"
"math/rand"
)

func main() {
// generate and shuffle 0000 - 9999
dest := make([]string, 10000)
for i, v := range rand.Perm(10000) {
dest[v] = fmt.Sprintf("%04d", i)
}
// write result to file
f, _ := os.Create("result.txt")
defer f.Close()
w := bufio.NewWriter(f)
for _, line := range dest {
fmt.Fprintln(w, line)
}
w.Flush()
}

``````

Hacky Perl/sh oneliner

``````perl -e '@v=("0000".."9999"); %x; print map { do { \$i=int(rand(@v)); } while(\$x{\$i}); \$x{\$i}=1; \$v[\$i] . "\n"} @v;' > hacked_pins.txt
``````

Generates a list of pins (@v) and then selects a random entry for every entry in the list (hacky use of map). %x is used to mark which entries already have been returned.

Love the bonus challenge!
Sent such a list to a friend working for a bank years ago.
This made it to the board of directors within minutes.
Still laughing and gasping - almost can't believe this impact :-D.

Just coming across this. I like finding and using old gems. For this, `jot` does just great.

``````jot -w %04d 9999 | shuf > /path/to/pins.txt
``````

Or for those on a Mac using GNU coreutils (probably from `brew`), you'd use `gshuf` instead of `shuf`:

``````jot -w %04d 9999 | gshuf > /path/to/pins.txt
``````

Of course, Ruby is just as elegant:

``````ruby -e 'puts ("0000"..."9999").to_a.shuffle' > /path/to/pins.txt
``````

... but on my machine the Ruby solution is about 95% slower than the `jot` version: 148ms vs. 8ms, respectively.

# Pharo

``````(file :='leaked_pins.txt' asFileReference) writeStreamDo: [ :s |
(0 to: 9999) shuffled do: [ :n | s << (n printPaddedWith: \$0 to: 4); cr ]].

SMTPClient
to: { 'poorcolleague@target.org' }
text: ('All the PIN numbers have been leaked, and you should be cautious and check, whether your PIN is contained in the file. ', file contents)
usingServer: 'somereplay.world.net'
``````

``````seq --equal-width 0 1 9999 | sort --random-sort > result.txt
``````

Easier to read and works with embedded Linux systems (BusyBox):

``````seq -w 0 1 9999 | shuf > result.txt
``````

Here's my Javascript solution for the basic challenge: gist.github.com/Alcha/99a4bebd18dc...

Gonna try the Bonus Challenge next 😊

### AWK:

``````

awk 'BEGIN{for(i=0;i<10000;i++){N[i]=sprintf("%04d",i)};while(i){j=int(10000*rand());if(N[j]){print N[j];delete N[j];i--}}}' > leaked_pins.txt
``````

``````ruby  -e 'puts (0..9999).to_a.shuffle.map {|e| "%04d" % e}' > pins.txt
``````

Vim/Bash:

``````9998O<esc>:%s/^/\=printf('%04d',line('.'))/<cr>:%!shuf<cr>:w leaked-pins.txt
``````
code of conduct - report abuse