('1' * N) !~ /^1?$|^(11+?)\1+$/
On the net, I found this piece of Ruby code that works for N >= 0 that determines whether or not N is a prime. From what I can tell, it looks like play with regex but I have no idea how it works. Could someone tell me how it works?
You can find a lengthy explanation of this code here:
http://www.noulakaz.net/weblog/2007/03/18/a-regular-expression-to-check-for-prime-numbers/
This is probably rather off-topic, but in Ruby 1.9, you can do this:
require 'mathn'
38749711234868463.prime?
=> false
require 'prime'
Prime.prime?(4)
# => false
Prime.prime?(5)
# => true
Or:
require 'prime'
Prime.instance.prime?(4)
# => false
Prime.instance.prime?(5)
# => true
See also What is the most brilliant regex you’ve ever used? (and yes, I can confirm that this regexp was originally written by Abigail. I've even heard her explain how it works :)
Greatest Common Divisor (gcd):
/^(1+)\1*=\1+$/.match('1' * x + '=' + '1' * y)[1].length
Both this and the is_prime one works in about the same way. It tries all combinations before giving up.
This one will try to split the first number in even parts, and match the second number with one or more of those parts. If it finds a match it returns the length of the selected part.
Yet another blog with a pretty good explanation: Famous Perl One-Liners Explained (part III)
If the length of a string of 1's is composite, then the string can be decomposed into multiple identical substrings, like 111111 -> 11 11 11
For example, 1111111111, has 10 1's, and it matches (11){5} or (11111){2}, where {2} means repeated 2 times.
111111111, has 9 1's, and it matches (111){3}.
By generalizing the count of 1's and the number in {}, the regexp is
/(1{2,}){2,}/.
However, 1{2,} can also be written as 11+, and (...){2,} can be rewritten as (...)\1+, with backreferences.
The ^1?$ part in the first alternation checks for 0 and 1-cases.
Related
I currently have a very large array of permutations, which is currently using a significant amount of RAM. This is the current code I have which SHOULD:
Count all but the occurrences where more than one '1' exists or three '2's exist in a row.
arr = [*1..3].repeated_permutation(30).to_a;
count = 0
arr.each do |x|
if not x.join('').include? '222' and x.count(1) < 2
count += 1
end
end
print count
So basically this results in a 24,360 element array, each of which have 30 elements.
I've tried to run it through Terminal but it literally ate through 14GB of RAM, and didn't move for 15 minutes, so I'm not sure whether the process froze while attempting to access more RAM or if it was still computing.
My question being: is there a faster way of doing this?
Thanks!
I am not sure what problem you try to solve. If your code is just an example for a more complex problem and you really need to check programatically every single permumation, then you might want to experiment with lazy:
[*1..3].repeated_permutation(30).lazy.each do ||
# your condition
end
Or you might want to make the nested iteratior very explicit:
[1,2,3].each do |x1|
[1,2,3].each do |x2|
[1,2,3].each do |x3|
# ...
[1,2,3].each do |x30|
permutation = [x1,x2,x3, ... , x30]
# your condition
end
end
end
end
end
But it feels wrong to me to solve this kind of problem with Ruby enumerables at all. Let's have a look at your strings:
111111111111111111111111111111
111111111111111111111111111112
111111111111111111111111111113
111111111111111111111111111121
111111111111111111111111111122
111111111111111111111111111123
111111111111111111111111111131
...
333333333333333333333333333323
333333333333333333333333333331
333333333333333333333333333332
333333333333333333333333333333
I suggest to just use enumerative combinatorics. Just look at the patterns and analyse (or count) how often your condition can be true. For example there are 28 indexes in your string at which a 222 substring could be place, only 27 for the 2222 substring... If you place a substring how likely is it that there is no 1 in the other parts of the string?
I think your problem is a mathematics problem, not a programming problem.
NB This is an incomplete answer, but I think the idea might give a push to the proper solution.
I can think of a following approach: let’s represent each permutation as a value in ternary number base, padded by zeroes:
1 = 000..00001
2 = 000..00002
3 = 000..00010
4 = 000..00011
5 = 000..00012
...
Now consider we restated the original task, treating zeroes as ones, ones as twos and twos as threes. So far so good.
The whole list of permutations would be represented by:
(1..3**30-1).map { |e| x = e.to_s(3).rjust(30, '0') }
Now we are to apply your conditions:
def do_calc permutation_count
(1..3**permutation_count-1).inject do |memo, e|
x = e.to_s(3).rjust(permutation_count, '0')
!x.include?('111') && x.count('0') < 2 ? memo + 1 : memo
end
Unfortunately, even for permutation_count == 20 it takes more than 5 minutes to calculate, so probably some additional steps are required. I will be thinking of further optimization. Currently I hope this will give you a hint to find the good approach yourself.
I have unsorted arrays as some_array. When I use some_array.max to get the max number, I get the following output. For:
some_array = ["1.10.0", "1.11.0", "1.12.0", "1.13.0", "1.14.0", "1.15.0", "1.16.0",
"1.16.1", "1.17.0", "1.18.0", "1.7.0", "1.8.0"]
I get 1.8.0 instead of 1.18.0. For:
some_array = ["1.11.0", "1.12.0", "1.13.0", "1.14.0", "1.14.1", "1.15.0", "1.16.0", "1.17.0", "1.18.0", "1.19.0", "1.5.0", "1.8.0", "1.9.0"]
I get 1.9.0 instead of 1.19.0.
To me, it looks like max is picking up the last value from the array. Shouldn't max print the maximum value in the array? Do I have to sort the array before using max? Is there any other way to get max value out of array?
The existing answers already point out the problem in your code. This is how you may write it:
some_array.max_by { |version| version.split(".").map(&:to_i) }
#=> "1.18.0"
The problem is that you are thinking that they are integers, but they're not - they're strings. So they get sorted lexicographically. That is to say, treat them like an alphabet. "1.8.0" is greater than "1.18.0", because the "8" is greater than the "1" character (in the 3rd position).
Look at the following random strings. They are in order:
"abcdef"
"abdghi"
"adaaaa"
Why are they in order? Because you look at the first character, and compare them. Then look at the next character, and compare them, etc. Now look at your example:
"1.18.0"
"1.8.0"
Look at the first character of each, it's a "1", it's equal. Look at the next character, both are ".", they're equal. Look at the next characters, "1" and "8". "1" comes before "8". Therefore, "1.8.0" must come lexicographically after "1.18.0".
If you want to treat them like integers, there are a few things you can do. 1) You can write your own sort method in a block, or 2) wrap the strings in some hand-made Version object, and then write the comparator there.
If you need help with these specific ideas, let us know.
Shouldn't max() print the maximum value in the array?
Yes. It should. And it is doing so, as you can see in the results you got.
Do I have to sort the array before using max()?
No.
Is there any other way to get max value out of array?
Yes. But you already got the max value.
this method checks character by character.
So, comparing 1.9.0 and 1.19.0 , it will give 1.9.0 as bigger than 1.19.0 because the part "1." is equal in both strings, but the next character is 9 in the first one, and 1 in the second one, so the method will say 1.9.0 is bigger since 9 comes later than 1 in ASCII code.
When you need to sort version numbers the Versionomy Gem helps a lot. It also handles all the edge cases, for example beta and RC versions: 1.8beta < 1.8RC < 1.8.
Using that gem you must change your code to something like this:
require 'versionomy'
some_array.max_by { |version| Versionomy.parse(version) }
I am trying to convert words/strings to numbers in Ruby for example:-
ONE => 1
TWO => 2
THREE => 3
FOUR => 4
etc...
I have seen many examples other way around (numbers to words); however, I am not been able to find an example of how to convert words to numbers. It would be great if I can get any insight or help on this.
This might help: http://www.rubyquiz.com/quiz25.html
EDIT: read the question incorrectly. As per my comment below, here's a way you could approach this.
If num_to_word(number) is your method of converting from a number to a word:
def number_hash_creator(min, max)
number_hash = {}
for num in (min..max)
number_hash[num_to_word(num)] == num
end
number_hash
end
Then do something like:
number_hash = number_hash_creator(min, max) # min and max are whatever you need them to be
number_hash['three']
=> 3
You could also append a similar method to the string class so that you could do things like "three".to_number
I created a hash up-to twenty for all words and only for tens(thirty, forty, fifty etc.). Using Reg-ex took off two words and added them for example twenty two is addition of 20+2=22; right now my script only works till hundred, but it can be extended for numbers over 100 and so on.
I think you will find this tutorial very interesting particularly the code near the bottom:
http://pine.fm/LearnToProgram/?Chapter=08
I play around with arrays and hashes quite a lot in ruby and end up with some code that looks like this:
sum = two_dimensional_array.select{|i|
i.collect{|j|
j.to_i
}.sum > 5
}.collect{|i|
i.collect{|j|
j ** 2
}.average
}.sum
(Let's all pretend that the above code sample makes sense now...)
The problem is that even though TextMate (my editor of choice) picks up simple {...} or do...end blocks quite easily, it can't figure out (which is understandable since even I can't find a "correct" way to fold the above) where the above blocks start and end to fold them.
How would you fold the above code sample?
PS: considering that it could have 2 levels of folding, I only care about the outer consecutive ones (the blocks with the i)
To be honest, something that convoluted is probably confusing TextMate as much as anyone else who has to maintain it, and that includes you in the future.
Whenever you see something that rolls up into a single value, it's a good case for using Enumerable#inject.
sum = two_dimensional_array.inject(0) do |sum, row|
# Convert row to Fixnum equivalent
row_i = row.collect { |i| i.to_i }
if (row_i.sum > 5)
sum += row_i.collect { |i| i ** 2 }.average
end
sum # Carry through to next inject call
end
What's odd in your example is you're using select to return the full array, allegedly converted using to_i, but in fact Enumerable#select does no such thing, and instead rejects any for which the function returns nil. I'm presuming that's none of your values.
Also depending on how your .average method is implemented, you may want to seed the inject call with 0.0 instead of 0 to use a floating-point value.
I am using ruby to calculate the Gunning Fog Index of some content that I have, I can successfully implement the algorithm described here:
Gunning Fog Index
I am using the below method to count the number of syllables in each word:
Tokenizer = /([aeiouy]{1,3})/
def count_syllables(word)
len = 0
if word[-3..-1] == 'ing' then
len += 1
word = word[0...-3]
end
got = word.scan(Tokenizer)
len += got.size()
if got.size() > 1 and got[-1] == ['e'] and
word[-1].chr() == 'e' and
word[-2].chr() != 'l' then
len -= 1
end
return len
end
It sometimes picks up words with only 2 syllables as having 3 syllables. Can anyone give any advice or is aware of a better method?
text = "The word logorrhoea is often used pejoratively to describe prose that is highly abstract and contains little concrete language. Since abstract writing is hard to visualize, it often seems as though it makes no sense and all the words are excessive. Writers in academic fields that concern themselves mostly with the abstract, such as philosophy and especially postmodernism, often fail to include extensive concrete examples of their ideas, and so a superficial examination of their work might lead one to believe that it is all nonsense."
# used to get rid of any puncuation
text = text.gsub!(/\W+/, ' ')
word_array = text.split(' ')
word_array.each do |word|
puts word if count_syllables(word) > 2
end
"themselves" is being counted as 3 but it's only 2
The function I give you before is based upon these simple rules outlined here:
Each vowel (a, e, i, o, u, y) in a
word counts as one syllable subject to
the following sub-rules:
Ignore final -ES, -ED, -E (except
for -LE)
Words of three letters or
less count as one syllable
Consecutive vowels count as one
syllable.
Here's the code:
def new_count(word)
word.downcase!
return 1 if word.length <= 3
word.sub!(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, '')
word.sub!(/^y/, '')
word.scan(/[aeiouy]{1,2}/).size
end
Obviously, this isn't perfect either, but all you'll ever get with something like this is a heuristic.
EDIT:
I changed the code slightly to handle a leading 'y' and fixed the regex to handle 'les' endings better (such as in "candles").
Here's a comparison using the text in the question:
# used to get rid of any puncuation
text = text.gsub!(/\W+/, ' ')
words = text.split(' ')
words.each do |word|
old = count_syllables(word.dup)
new = new_count(word.dup)
puts "#{word}: \t#{old}\t#{new}" if old != new
end
The output is:
logorrhoea: 3 4
used: 2 1
makes: 2 1
themselves: 3 2
So it appears to be an improvement.
One thing you ought to do is teach your algorithm about diphthongs. If I'm reading your code correctly, it would incorrectly flag "aid" as having two syllables.
You can also add "es" and the like to your special-case endings (you already have "ing") and just not count it as a syllable, but that might still result in some miscounts.
Finally, for best accuracy, you should convert your input to a spelling scheme or alphabet that has a definite relationship to the word's pronunciation. With your "themselves" example, the algorithm has no reliable way to know that the "e" "ves" is dropped. However, if you respelled it as "themselvz", or taught the algorithm the IPA and fed it [ðəmsɛlvz], it becomes very clear that the word is only pronounced with two syllables. That, of course, assumes you have control over the input, and is probably more work than just counting the syllables yourself.
To begin with it seems you should decrement len for the suffixes that should be excluded.
len-=1 if /.*[ing,es,ed]$/.match(word)
You could also check out Lingua::EN::Readability.
It can also calculate several readability measures, such as a Fog Index and a Flesch-Kincaid level.
PS. I think I know where you got the function from. DS.
There is also a rubygem called Odyssey that calculates Gunning Fog, along with some of the other popular ones (Flesch-Kincaid, SMOG, etc.)