How can I determine that one alphanumeric ID is greater than another in Ruby? - ruby

Right now I am working on a project that issues IDs consisting of both letters and numbers, for example 345A22. I need this program to be able to tell that for example, 345B22 is greater than 345A22. I can't assume that the letters will be in the same position all the time (ie we do have some id's with 22335Q) but when I compare two numbers the letters will be in the same position.
How do I accomplish this in Ruby?

You can use the String#<=> method to compare strings. See documentation here.
>> "345B22" <=> "345A22"
=> 1
Where the 1 return value means that 345B22 is greater.

If a simple string comparison won't do the trick (e.g. different lengths, etc.), try converting the IDs (assuming they all match ^[0-9A-Z]*$) into integers by treating them as base36-encoded data.

In Ruby strings have the same comparison methods as numbers have.
2 > 1 #=> true
"2" > "1" #=> true
"B" > "A" #=> true

Not sure I understand your question, but I'm guessing that you mentally parse the ids into components (so 345B22 is 345, B, 22) and then are wishing for a numeric sort for things that are numbers (i.e., 12 > 2) and a string sort for things that are strings (AB < B).
If this is what you intend, something like the following would do the trick:
ids.sort_by do |id|
id.scan(/\d+|[a-zA-Z]+/).map {|c| c =~ /\d/ ? c.rjust(20) : c.ljust(20) }.join
end
What this does is extract out all consecutive numbers or letters and then justify them right or left based on their type, concatenates the result and then sorts based on this (expanded and canonicalized) id.

Related

How to sort an array using only the first 5 characters of a string in Ruby?

So, say I have an array of strings such as:
["74712 Don", "48342 Cindy", "50912 Nick"]
and I want to sort them by the number in front of the name. How would I sort by only the first 5 characters of each element (while also evaluating them as numbers)?
Thanks
Assuming you wish to sort by the leading digits of the strings, you can do the following:
["74712 Don", "48342 Cindy", "50912 Nick"].sort_by(&:to_i)
#=> ["48342 Cindy", "50912 Nick", "74712 Don"]
This works because String#to_i ignores "extraneous characters past the end of a valid number".
If some elements of the array may have more than five leading digits, but only the first five are to be considered, one would use
["74712 Don", "48342 Cindy", "209124 Nick"].sort_by { |s|
s[0,5].to_i }
#=> ["209124 Nick", "48342 Cindy", "74712 Don"]

How to store a list of small numbers in Postgres

I have a long list of small numbers, all of them < 16 but there can be more than 10000 of them in a unique list.
I get the values as a comma separated list, like:
6,12,10,2,2,2,6,12,8,2,2,6,10,2,4,12,14,10,2, .... lots and lots of numbers
And finally I need to store the values in a database in the most efficient way in order to be read back and processed again ... as a string, comma separated values.
I was thinking of sort of storing them in a big TEXT field ... however I find that adding all the commas in there would be a waste of space.
I am wondering if there is any best practice for this scenario.
For more technical details:
for Database I have to use Postgres (and I am sort of beginner in this field), and the programming language is Ruby (also beginner :) )
For a fast and reasonably space efficient solution, you could simply write a hexadecimal string :
string = '6,12,10,2,2,2,6,12,8,2,2,6,10,2,4,12,14,10,2'
p string.split(',').map { |v| v.to_i.to_s(16) }.join
# "6ca2226c8226a24cea2"
p '6ca2226c8226a24cea2'.each_char.map { |c| c.to_i(16) }.join(',')
# "6,12,10,2,2,2,6,12,8,2,2,6,10,2,4,12,14,10,2"
It brings the advantage of being easily readable by any DB and any program.
Also, it works even if there are leading 0s in the string : "0,0,6".
If you have an even number of elements, you could pack 2 hexa characters into one byte, to divide the string length by 2.
numbers = "6,12,10,2,2,2,6,12,8,2,2,6,10,2,4,12,14,10,2"
numbers.split(',')
.map { |n| n.to_i.to_s(2).rjust(4, '0') }
.join
.to_i(2)
.to_s(36)
#⇒ "57ymwcgbl1umt2a"
"57ymwcgbl1umt2a".to_i(36)
.to_s(2)
.tap { |e| e.prepend('0') until (e.length % 4).zero? }
.scan(/.{4}/)
.map { |e| e.to_i(2).to_s }
.join(',')
#⇒ "6,12,10,2,2,2,6,12,8,2,2,6,10,2,4,12,14,10,2"

Lua: Inverse of string.char()?

I'm wondering if there is a function that does the exact opposite of string.char(). It would be convenient to get a number value from letters in order to sort things alphabetically.
string.byte()
Is probably what you're looking for.
To get the first UTF-8 Byte of a string, you can use either string.byte or str:byte() where str is your string in question.
However, if you're sorting a table, or doing a sort in general, Lua actually has you covered! You can compare two strings as if they were numbers! "A" < "B" returns true and "B" < "A" returns false. This also works for multiple letters in a string. "Ba" > "Aa" and "Ab" > "Aa" and so on. So you can do table.sort(t) or if you're sorting by a sub value, table.sort(t,function(a,b) return a.text < b.text end). Hope this helps!

Parse many numbers containing commas from string

I have a series of strings that all include 1 or many numbers (a number in this case would be 123,123,123) in the following format
"This is a number 123,124,123"
"These are some more numbers 123,345,123; 231,123,123; 124,152,123"
"This one is an odd situation 123,124,125; 123,123,123; more text"
What is the cleanest way to parse these numbers into either an array or a string that I can split that looks like this?
"123,124,123"
"123,345,123;231,123,123;124,152,123"
"123,124,125;123,123,123;"
Ultimately I want to be able to separate out the numbers like this.
"123,124,123"
"123,345,123" "231,123,123" "124,152,123"
"123,124,125" "123,123,123"
Currently attempting to use
"string".scan( /\d/ )
but obviously this is only giving me the numbers without the commas and also not separated properly.
Do it like this
string.scan(/[\d,]+/)
Another way would be to remove the unwanted characters.
arr = ["This is a number 123,124,123",
"These are some more numbers 123,345,123; 231,123,123; 124,152,123",
"This one is an odd situation 123,124,125; 123,123,123; more text"]
arr.map { |str| str.gsub(/[^\s\d,]+/,'').split }
#=> [["123,124,123"],
# ["123,345,123", "231,123,123", "124,152,123"],
# ["123,124,125", "123,123,123"]]
Regex that matches your numbers is \d{1,3}(,\d{3})*

String that can contain multiple numbers - how do I extract the longest number?

I have a string that
contains at least one number
can contain multiple numbers
Some examples are:
https://www.facebook.com/permalink.php?story_fbid=53199604568&id=218700384
https://www.facebook.com/username_13/posts/101505775425651120
https://www.facebook.com/username/posts/101505775425699820
I need a way to extract the longest number from the string. So for the 3 strings above, it would extract
53199604568
101505775425651120
101505775425699820
How can I do this?
#get the lines first
text = <<ENDTEXT
https://www.facebook.com/permalink.php?story_fbid=53199604568&id=218700384
https://www.facebook.com/username_13/posts/101505775425651120
https://www.facebook.com/username/posts/101505775425699820
ENDTEXT
lines = text.split("\n")
#this bit is the actual answer to your question
lines.collect{|line| line.scan(/\d+/).sort_by(&:length).last}
Note that i'm returning the numbers as strings here. You could convert them to numbers with to_i
parse the list (to get an int array), then use the Max function. array.Max for syntax.
s = "https://www.facebook.com/permalink.php?story_fbid=53199604568&id=218700384"
s.scan(/\d+/).max{|a,b| a.length <=> b.length}.to_i

Resources