List comprehension in Haskell, Python and Ruby - python

I have started looking at the project Euler site as a way to learn Haskell, and improve my Python and Ruby. I think the Haskell and Python versions are ok, but I'm sure there must be a cleaner way for Ruby.
This is not about how can I make one language look like another one.
This is Problem 1:
Q: Add all the natural numbers below one thousand that are multiples of 3 or 5.
Haskell:
sum [ x | x <- [1..999], mod x 3 == 0 || mod x 5 == 0 ]
Python:
sum ( [ x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0 ] )
Ruby:
(1..999) . map {|x| x if x % 3 == 0 || x % 5 == 0 } . compact . inject(:+)
They all give the same answer.
OK, so Python can become:
sum ( x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0 )
it is now a generator (a good thing as we are not storing the list)
but even more fun is:
sum( set(range(0,1000,3)) | set(range(0,1000,5)) )
For some reason I was looking at this again and tried a summation approach which should be constant time. In Python 3:
def step_sum(mn,mx,step):
amax = mx - (mx - mn) % step
return (mn + amax) * ((1 + ((amax - mn) / step)) / 2)
step_sum(3,999,3) + step_sum(5,999,5) - step_sum(15,999,15)
Ruby can become:
(1..999) . select {|x| x % 3 == 0 || x % 5 == 0} . inject(:+)
or
(1..999) . select {|x| x % 3 == 0 or x % 5 == 0} . reduce(:+)
I am presuming as unlike map, select doesn't produce 'nul' and therefore there is no need to call compact. nice.
Haskell can also be:
let ƒ n = sum [0,n..999] in ƒ 3 + ƒ 5 - ƒ 15
or to be clearer:
let ƒ n = sum [ 0 , n .. 999 ] in ƒ 3 + ƒ 5 - ƒ (lcm 3 5)
as a function that lets us provide the two numbers ourselves:
ƒ :: (Integral a) => a -> a -> a
ƒ x y = let ƒ n = sum [0,n..999] in ƒ x + ƒ y - ƒ (lcm x y)

For Haskell I like
let s n = sum [0,n..999] in s 3 + s 5 - s 15
or
sum $ filter ((>1).(gcd 15)) [0..999]
For fun the Rube-Goldberg version:
import Data.Bits
sum $ zipWith (*) [1..999] $ zipWith (.|.) (cycle [0,0,1]) (cycle [0,0,0,0,1])
Okay, explanation time.
The first version defines a little function s that sums up all multiples of n up to 999. If we sum all multiples of 3 and all multiples of 5, we included all multiples of 15 twice (once in every list), hence we need to subtract them one time.
The second version uses the fact that 3 and 5 are primes. If a number contains one or both of the factors 3 and 5, the gcd of this number and 15 will be 3, 5 or 15, so in every case the gcd will be bigger than one. For other numbers without a common factor with 15 the gcd becomes 1. This is a nice trick to test both conditions in one step. But be careful, it won't work for arbitrary numbers, e.g. when we had 4 and 9, the test gdc x 36 > 1 won't work, as gcd 6 36 == 6, but neither mod 6 4 == 0 nor mod 6 9 == 0.
The third version is quite funny. cycle repeats a list over and over. cycle [0,0,1] codes the "divisibility pattern" for 3, and cycle [0,0,0,0,1] does the same for 5. Then we "or" both lists together using zipWith, which gives us [0,0,1,0,1,1,0,0,1,1,0,1...]. Now we use zipWith again to multiply this with the actual numbers, resulting in [0,0,3,0,5,6,0,0,9,10,0,12...]. Then we just add it up.
Knowing different ways to do the same thing might be wasteful for other languages, but for Haskell it is essential. You need to spot patterns, pick up tricks and idioms, and play around a lot in order to gain the mental flexibility to use this language effectively. Challenges like the project Euler problems are a good opportunity to do so.

Try this for Ruby:
(1..999).select {|x| x % 3 == 0 or x % 5 == 0}.reduce(:+)
Or a little different approach:
(1..999).reduce(0) {|m, x| (x % 3 == 0 or x % 5 == 0) ? m+x : m }

Not a list comprehension, I know, but to solve that I would use:
3*((999/3)**2+999/3)/2+5*((999/5)**2+999/5)/2-15*((999/15)**2+999/15)/2
Faster then any list comprehension one might come up with, and works in any language ;)
Only posting to show another way of looking at the same problem using http://en.wikipedia.org/wiki/Summation.

I think the following is a better Ruby one:
(1..999).select{|x| x % 3 == 0 || x % 5 == 0}.reduce(:+)

Try something like this:
(1...1000).inject(0) do |sum, i|
if (i % 3 == 0) or (i % 5 == 0)
sum + i
else
sum
end

Related

More efficient way to calculate the nth term

I have the recurrence relation : (n-2)an = 2(4n-9)an-1 - (15n-38)an-2 - 2(2n-5)an-3 with initial conditions being a0 = 0, a1 = 1 and a2 = 3. I mainly want to calculate an mod n and 2n mod n for all odd composite numbers n from 1 up to say 2.5 million.
I have written down a code in Python. Using sympy and memoization, I did the computation for an mod n but it took it more than 2 hours. It got worse when I tried it for a2n mod n. One main reason for the slowness is that the recurrence has non-constant coefficients. Are there more efficient codes that I could use? Or would it help to do this on some other language (which preferably should have an in-built function or a function from some package that can be used directly for the primality testing part of the code)?
This is my code.
from functools import lru_cache
import sympy
#lru_cache(maxsize = 1000)
def f(n):
if n==0:
return 0
elif n==1:
return 1
elif n==2:
return 3
else:
return ((2*((4*n)-9)*f(n-1)) - (((15*n)-38)*f(n-2)) - (2*((2*n)-5)*f(n-3)))//(n-2)
for n in range(1,2500000,2):
if sympy.isprime(n)==False:
print(n,f(n)%n)
if n%10000==1:
print(n,'check')
The last 'if' statement is just to check how much progress is being made.
For a somewhat faster approach avoiding any memory issues, you could calculate the an directly in sequence, while always retaining only the last three values in a queue:
from collections import deque
a = deque([0, 1, 3])
for n in range(3, 2_500_000):
a.append(((8 * n - 18) * a[2]
- (15 * n - 38) * a[1]
- (4 * n - 10) * a.popleft())
// (n - 2))
if n % 2 == 1:
print(n, a[2] % n)
3 2
5 0
7 6
9 7
11 1
[...]
2499989 1
2499991 921156
2499993 1210390
2499995 1460120
2499997 2499996
2499999 1195814
This took about 50 minutes on my PC. Note I avoided the isprime() call in view of Rodrigo's comment.

Python - Simple expression to find greatest odd number below n

As the title already states I'm searching for a simple expression to find the greatest odd number below some n:
I want to inline this code into an arithmetic expression and don't want to use the ternary operator. Is there an arithmetic way to find this odd number?
How about this where testNumber is your variable
(testNumber - 1 >> 1 << 1) | 1 # LESS THAN OR EQUAL TO
(testNumber - 2 >> 1 << 1) | 1 # LESS THAN
The following is a purely arithmetic solution:
def greatest_odd_number_below(n): return (n//2)*2 - 1
EDIT 1: For floating point inputs:
# python 2 solution
from math import ceil
def greatest_odd_number_below_floats(n): return (int(ceil(n))//2)*2 - 1
EDIT 2: As #PM 2Ring pointed out in the comments, math.ceil returns an int in python 3, so you can remove the additional casting to int.
# python 3 solution
from math import ceil
def greatest_odd_number_below_floats(n): return (ceil(n)//2)*2 - 1
Another way:
n - n%2 - 1
Demo:
>>> for n in range(10):
print(n, '->', n - n%2 - 1)
0 -> -1
1 -> -1
2 -> 1
3 -> 1
4 -> 3
5 -> 3
6 -> 5
7 -> 5
8 -> 7
9 -> 7
babygameOver is right. There is no such built-in function, so you should implement it by yourself.
Just to put my 2 cents, you can use lambda expressions. Looks pretty simple.
>>> odd = lambda n: n-1 if n % 2 == 1 else n - 1
>>> odd(3)
3
>>> odd(744)
743
Without conditional you can't solve the scenario.
but you can do this way as you have done in yours.
def odd(n):
if n%2==0:
return n-1
return n
print(odd(3))
Hope this helps

Python - Finding the difference between 2 numbers

So I'm trying to find a way to find the difference between 3 ints;
a, b, c
so I need to find the difference between a - b and the difference between b - c
and then print true if the difference is the same, else printing false.
I've been attempting to use the abs() function but can't seem to get the result I need. any help would be appreciated.
Here is the problem statement:
Given three ints, a b c, one of them is small, one is medium and
one is large. Print True if the three values are evenly spaced,
so the difference between small and medium is the same as the
difference between medium and large.
this is what i have so far;
a = int(input())
b = int(input())
c = int(input())
if abs(a-b) == abs(b-c) :
print("True")
else :
print("False")
#
Test Input Expected Actual
1 4 6 2 True False
2 6 2 4 True False
3 10 9 11 True False
Based on the problem description, it sounds like you need to sort the numbers first:
numbers = sorted(int(input()) for _ in range(3))
print(numbers[1] - numbers[0] == numbers[2] - numbers[1])
You have 3 possible "middle" numbers, therefore you need to perform 3 comparisons.
x = abs(a - b)
y = abs(a - c)
z = abs(b - c)
if (x == y) or (x == z) or (y == z):
...

Big O notation in python

Does anyone know of any good resources to learn big o notation? In particular learning how to walk through some code and being able to see that it would be O(N^2) or O(logN)? Preferably something that can tell me why a code like this is equal to O(N log N)
def complex(numbers):
N = len(numbers)
result = 0
for i in range(N):
j = 1
while j < N:
result += numbers[i]*numbers[j]
j = j*2
return result
Thanks!
To start, let me define to you what O(N log N) is. It means, that the program will run at most N log N operations, i.e. it has a upper bound of ~N log N (where N is the size of the input).
Now here, your N is the size of numbers, or your code:
N = len(numbers)
Notice that the first for loop runs from 0 to N-1, for a total of N operations. This is where the first N comes from.
-
Then, where does the log N come from? It is from the while loop.
In the while loop, you keep multiplying 2 to j until j is greater or equal than N.
This will be completed when we have executed the loop ~log2(N) times, which describes how many times we have to multiply j by 2 to get to N. For example, log2(8) = 3, because we multiply j by 2 three times to get 8:
#ofmult. j oldj
1 2 2 <- 1 * 2
2 4 4 <- 2 * 2
3 8 8 <- 4 * 2
To better illustrate this, I have added a print statement in your code, for i and j:
def complex(numbers):
N = len(numbers)
result = 0
for i in range(N):
j = 1
while j < N:
print(str(i) + " " + str(j))
result += numbers[i]*numbers[j]
j = j*2
return result
When this is run:
>>> complex([2,3,5,1,5,3,7,3])
This is what is outputted:
0 1
0 2
0 4
1 1
1 2
1 4
2 1
2 2
2 4
3 1
3 2
3 4
4 1
4 2
4 4
5 1
5 2
5 4
6 1
6 2
6 4
7 1
7 2
7 4
Notice how our i goes from 0...7 (N times for a total of O(N) ), and the second part, there are always 3 ( log2(N) ) j-outputs for every i.
So, the code is O(N log2 N).
Also, some good websites I would recommend are:
https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/
And, a video from a lecture series from a Stanford professor:
https://www.youtube.com/watch?v=eNsKNfFUqFo
When you multiply j by 2, you're effectively saying "I've done half the remaining problem!". At each step in the while loop, you're solving half the remaining problem. Therefore if your problem is x size, then the number of iterations required would be i = log_2 x, which we just say is log x. In this case your x is just equal to N.
The for loop has you do the above section N times again, so you get N * log N.
We use O(N log N) to mean that, at each step, we might do any CONSTANT number of things (for example inside the while loop I might do a billion operations), but we don't care about this constant, because generally N is usually bigger, and can get arbitrarily big (beyond a certain size point, even a billion is nothing in comparison to what N COULD be, i.e. a googol). Hence we have O(N log N).
Here's a short crash course in the form of a pdf:
http://www1.icsi.berkeley.edu/~barath/cs61b-summer2002/lectures/lecture10.pdf
Here's a short crash course in the form of a lecture:
https://www.youtube.com/watch?v=VIS4YDpuP98

Writing a simple function using while

A Python HOMEWORK Assignment asks me to write a function “that takes as input a positive whole number, and prints out a multiplication, table showing all the whole number multiplications up to and including the input number.”(Also using the while loop)
# This is an example of the output of the function
print_multiplication_table(3)
>>> 1 * 1 = 1
>>> 1 * 2 = 2
>>> 1 * 3 = 3
>>> 2 * 1 = 2
>>> 2 * 2 = 4
>>> 2 * 3 = 6
>>> 3 * 1 = 3
>>> 3 * 2 = 6
>>> 3 * 3 = 9
I know how to start, but don’t know what to do next. I just need some help with the algorithm. Please DO NOT WRITE THE CORRECT CODE, because I want to learn. Instead tell me the logic and reasoning.
Here is my reasoning:
The function should multiply all real numbers to the given value(n) times 1 less than n or (n-1)
The function should multiply all real numbers to n(including n) times two less than n or (n-2)
The function should multiply all real numbers to n(including n) times three less than n or (n-3) and so on... until we reach n
When the function reaches n, the function should also multiply all real numbers to n(including n) times n
The function should then stop or in the while loop "break"
Then the function has to print the results
So this is what I have so far:
def print_multiplication_table(n): # n for a number
if n >=0:
while somehting:
# The code rest of the code that I need help on
else:
return "The input is not a positive whole number.Try anohter input!"
Edit: Here's what I have after all the wonderful answers from everyone
"""
i * j = answer
i is counting from 1 to n
for each i, j is counting from 1 to n
"""
def print_multiplication_table(n): # n for a number
if n >=0:
i = 0
j = 0
while i <n:
i = i + 1
while j <i:
j = j + 1
answer = i * j
print i, " * ",j,"=",answer
else:
return "The input is not a positive whole number.Try another input!"
It's still not completely done!
For example:
print_multiplication_table(2)
# The output
>>>1 * 1 = 1
>>>2 * 2 = 4
And NOT
>>> 1 * 1 = 1
>>> 1 * 2 = 2
>>> 2 * 1 = 2
>>> 2 * 2 = 4
What am I doing wrong?
I'm a little mad about the while loop requirement, because for loops are better suited for this in Python. But learning is learning!
Let's think. Why do a While True? That will never terminate without a break statement, which I think is kind of lame. How about another condition?
What about variables? I think you might need two. One for each number you want to multiply. And make sure you add to them in the while loop.
I'm happy to add to this answer if you need more help.
Your logic is pretty good. But here's a summary of mine:
stop the loop when the product of the 2 numbers is n * n.
In the mean time, print each number and their product. If the first number isn't n, increment it. Once that's n, start incrementing the second one. (This could be done with if statements, but nested loops would be better.) If they're both n, the while block will break because the condition will be met.
As per your comment, here's a little piece of hint-y psuedocode:
while something:
while something else:
do something fun
j += 1
i += 1
where should original assignment of i and j go? What is something, something else, and something fun?
This problem is better implemented using nested loops since you have two counters. First figure out the limits (start, end values) for the two counters. Initialize your counters to lower limits at the beginning of the function, and test the upper limits in the while loops.
The first step towards being able to produce a certain output is to recognize the pattern in that output.
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
The number on the right of = should be trivial to determine, since we can calculate it by multiplying the other two numbers on each row; obtaining those is the core of the assignment. Think of the two operands of * as two counters, let's call them i and j. We can see that i is counting from 1 to 3, but for each i, j is counting from 1 to 3 (resulting in a total of 9 rows; more generally there will be n2 rows). Therefore, you might try using nested loops, one to loop i (from 1 to n) and another to loop j (from 1 to n) for each i. On each iteration of the nested loop, you can print the string containing i, j and i*j in the desired format.

Categories

Resources