Ruby Permutation (Builtin) - Result does not contain adjacent identical letters - ruby

Thank you for your help yesterday and for teaching me something new as well. :)
I have another question based on permutation... the algorithm I have works however I have the issue that identical adjacent characters are missing from the list generated.
For example, if I have the character list a-z,0-9,- and let's say that the maximum length is 2, then I should see aa, bb, cc, dd, ee, ff, etc. ad nauseum.
length = 1
alphabet = [('a'..'z').to_a, ('0'..'9').to_a, ('-').to_a].flatten
prefix = 'file-'
suffix = '.txt'
while length < 3
alphabet.permutation(length).each do |x|
#name = prefix+x.join('').to_s+suffix
puts #name
end
length += 1
end
However, I am only seeing the following:
file-ba.txt
file-bc.txt
note the missing "bb" and this continues on until the program is finished.
I am sure I am missing something, just not sure what?

I think you want to use repeated_permutation instead of permutation.
http://www.ruby-doc.org/core/classes/Array.html#M000289
It will generate all permutations including "file-bb.txt".

That's what a permutation is. The only 6 permutations of [1,2,3] are
123
132
213
231
312
321

Related

How to get the randrange equivalent of python in Ruby

I want to get a random value between 0 and 20 but skips by 3, like the python equivalent of:
random.randrange(0,20, 3)
Here's a one-liner:
(0...20).to_a.keep_if {|z| z % 3 == 0}.sample
And bjhaid's example will work if you make the top number the first number that is equal or greater that is divisible by 3, i.e.:
rand(21 / 3) * 3
But you would have to manually set that upper number depending on what your slice size and upper number are.
My one-liner is kind of ugly to me, if I were using it in just one place in an entire program I might use it. but if I was going to re-use it I'd make a method: edit I just noticed #cremno answer in the comments. I like their step version better than mine. I'd use that in a method:
def randrange(lower, upper, grouping)
(lower...upper).step(grouping).to_a.sample
end
my old method...
def randrange(lower, upper, grouping)
arr = (lower...upper).to_a.keep_if {|i| i % grouping == 0}
arr.sample
end

Iteration order

I'm working on Project Euler problem #4:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers.
My code as follows is wrong:
def ispalindrome?(number)
number.to_s == number.to_s.reverse
end
palindromes = []
(100..999).each { |x|
(100..999).each { |y|
palindromes.push (x * y) if ispalindrome?(x * y)
}
}
palindromes.last # => 580085
What's going on here?
This has nothing to do with ruby. Simple math :)
Replace palindromes.last with palindromes.max
As someone else said, replacing palindromes.last with palindromes.max will work.
The reason is that, as products of three-digit numbers, 580085 = 995 * 583 and 906609 = 993 * 913.
Think carefully about the order in which you consider pairs of x and y. If you consider (993, 913) and then later (995, 583) (as happens in the first and third examples), then the last palindrome found will be 580085.
You just forgot to sort your array before taking the value, I used your code from the first try just added
palindromes.sort
and it gave me 906609
The problem is that you are not returning the biggest number but the last number that was added , and it depends on the order you loop through the numbers.
you need to change your last command to:
puts palindromes.max

All possible products

I'm trying to find all possible product of two 3-digit numbers. When I work with small ranges, I'm able to get an output in short amount of time but when the ranges are big, it seems to take really long time. Is there any way to to shorten the time to get the result?
The problem I'm working on is:
"A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers."
a = []
for x in 100..999
for y in 100..999
num = (x * y)
unless a.include? num
a.push num
end
end
end
p a
This is going to compute 100 x 101 and 101 x 100 separately, even though they're not going to be pushed to the array since they're already in it.
I'm bad at math, but maybe every time x goes up, y's minimum range can go up since that one was just used? people who are better at math can tell me if this is going to start missing numbers.
z= 100
for x in 100..999
for y in z..999
num = (x * y)
unless a.include? num
a.push num
end
z = z+1
end
end
I think doing this might make the "unless a.include? num" line unnecessary, too.
Looking at your code a quick optimization you can make is to use a set rather than an array to store the already computed products.
Since a is an array, a.include?(num) will have to iterate through the entire list of elements before returning true / false.
If a were to be a set, a.include?(num) will return in sub linear time.
Example:
require 'set'
a = Set.new
for x in 100..999
for y in 100..999
num = (x * y)
unless a.include? num
a.add(num)
end
end
end
puts a.to_a.join(", ")
Moreover one of the nice properties of a set is that it only stores unique elements so the following would be equivalent:
require 'set'
a = Set.new
for x in 100..999
for y in 100..999
num = (x * y)
a.add(num)
end
end
puts a.to_a.join(", ")
What are you really trying to do, i.e. what is the original problem, and why do you need all of these products?
Are you printing every single one out? Is someone asking you for a concrete list of every single one?
If not, there is likely a better way to deal with this problem. For example, if all you wanted is to check if a number X will be an element in "that list of products", all you'd have to do is:
range = 100..999
range.any? { |i| range.include?(x / i) }

How to program the below text format logic in ruby to validate a text field

I have a text field where it accepts only the text that satisfies the below criteria:
Text format of the below type where 'A' can be any random alphabets, 'D' is any numerical digit, but last digit is sum of all other digits modulo 10.
AAD-AAA-DDD
for example:
KN3-MNO-41_, this means the last digit is: 3 + 4 + 1 = 8, so it becomes: KN3-MNO-418
HK5-SFO-32_, this means the last digit is: 5 + 3 + 2 = 10, so it becomes HK5-SFO-320
I am in my intial learning of ruby, please help me: so how do I include these checks in the script and validate that the input text meets the criteria.
Thanks
def valid?(w)
w.match(/^[a-z][a-z]\d-[a-z][a-z][a-z]-\d\d\d$/i) and
([2,8,9].sum {|i| w[i].to_i} % 10 == w[10].to_i)
end
Here's a wild whack at it:
REGEX = /^([a-z]{2})(\d)-([a-z]{3})-(\d)(\d)(\d)$/i
STRINGS = %w[
KN3-MNO-418
HK5-SFO-320
KN3-MNO-419
HK5-SFO-321
]
def valid?(str)
chars1, d1, chars2, d2, d3, chksum = REGEX.match(str).captures
([d1, d2, d3].map(&:to_i).inject(:+) % 10) == chksum.to_i
end
STRINGS.each do |s|
puts valid?(s)
end
Running that outputs:
true
true
false
false
For fun and profit you can change the match assignment to:
_, d1, _, d2, d3, chksum = REGEX.match(str).captures
and/or the calculation to:
([d1, d2, d3].inject(0) { |m, s| m += s.to_i } % 10) == chksum.to_i
Now, that's sure to be as bewildering to you as it is to me, so I'll break it down:
/^([a-z]{2})(\d)-([a-z]{3})-(\d)(\d)(\d)$/i means:
Start at the beginning of the string and find two characters between "a".."z", followed by...
A single digit, followed by...
A hyphen, followed by...
Three characters between "a".."z", followed by another hyphen and...
Two separate digits and the checksum digit.
REGEX.match(str).captures matches the pattern to the string. captures returns an array of captured values from the string. "captures" are the parts in the pattern between parenthesis.
The results of captures is assigned to the local variables in parallel. Sweet.
([d1, d2, d3].map(&:to_i).inject(:+) % 10) == chksum.to_i is the part that makes us go "wheeeee!!!":
[d1, d2, d3].map(&:to_i) converts an array of strings to an array of integers...
inject(:+) is Ruby magic for "add all the elements of the array together."...
% 10 is modulo 10. Look up modolo, it's your new friend.
The rest you can figure out.

How do I modify the Damerau-Levenshtein algorithm, such that it also includes the start index, and the end index of the larger substring?

Here is my code:
#http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
# used for fuzzy matching of two strings
# for indexing, seq2 must be the parent string
def dameraulevenshtein(seq1, seq2)
oneago = nil
min = 100000000000 #index
max = 0 #index
thisrow = (1..seq2.size).to_a + [0]
seq1.size.times do |x|
twoago, oneago, thisrow = oneago, thisrow, [0] * seq2.size + [x + 1]
seq2.size.times do |y|
delcost = oneago[y] + 1
addcost = thisrow[y - 1] + 1
subcost = oneago[y - 1] + ((seq1[x] != seq2[y]) ? 1 : 0)
thisrow[y] = [delcost, addcost, subcost].min
if (x > 0 and y > 0 and seq1[x] == seq2[y-1] and seq1[x-1] == seq2[y] and seq1[x] != seq2[y])
thisrow[y] = [thisrow[y], twoago[y-2] + 1].min
end
end
end
return thisrow[seq2.size - 1], min, max
end
there has to be someway to get the starting and ending index of substring, seq1, withing parent string, seq2, right?
I'm not entirely sure how this algorithm works, even after reading the wiki article on it. I mean, I understand the highest level explanation, as it finds the insertion, deletion, and transposition difference (the lines in the second loop).. but beyond that. I'm a bit lost.
Here is an example of something that I wan to be able to do with this (^):
substring = "hello there"
search_string = "uh,\n\thello\n\t there"
the indexes should be:
start: 5
end: 18 (last char of string)
Ideally, the search_string will never be modified. But, I guess I could take out all the white space characters (since there are only.. 3? \n \r and \t) store the indexes of each white space character, get the indexes of my substring, and then re-add in the white space characters, making sure to compensate the substring's indexes as I offset them with the white space characters that were originally in there in the first place. -- but if this could all be done in the same method, that would be amazing, as the algorithm is already O(n^2).. =(
At some point, I'd like to only allow white space characters to split up the substring (s1).. but one thing at a time
I don't think this algorithm is the right choice for what you want to do. The algorithm is simply calculating the distance between two strings in terms of the number of modifications you need to make to turn one string into another. If we rename your function to dlmatch for brevity and only return the distance, then we have:
dlmatch("hello there", "uh, \n\thello\n\t there"
=> 7
meaning that you can convert one string into the other in 7 steps (effectively by removing seven characters from the second). The problem is that 7 steps is a pretty big difference:
dlmatch("hello there", "panda here"
=> 6
This would actually imply that "hello there" and "panda here" are closer matches than the first example.
If what you are trying to do is "find a substring that mostly matches", I think you are stuck with an O(n^3) algorithm as you feed the first string to a series of substrings of the second string, and then selecting the substring that provides you the closest match.
Alternatively, you may be better off trying to do pre-processing on the search string and then doing regexp matching with the substring. For example, you could strip off all special characters and then build a regexp that looks for words in the substring that are case insensitive and can have any amount of whitespace between them.

Resources