#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    39
    Rep Power
    2

    Code explanation


    Hello. I have this bit of code, but I am not sure what is going on exactly. I know it is taking the multiples of 3 and 5 and adding them, but I am not sure how the code actually accomplishes it.

    Code:
    sum(i for i in range(1,1000) if (i % 3 == 0) or (i % 5 == 0))
    Any explanation would be appreciated
  2. #2
  3. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,638
    Rep Power
    4247
    It is using a feature of python called list comprehension (google for that term).
    Basically, try doing this:
    Code:
    print( [i for i in range(1,1000) if (i % 3 == 0) or (i % 5 == 0)] )
    Basically, this expression:
    [i for i in range(1,1000) if (i % 3 == 0) or (i % 5 == 0)]
    says:
    1. Take i from 1 to 999 (the "for i in range(1,1000)" bit)
    2. Check if i is divisible by 3 or 5 (the "if (i % 3 == 0) or (i % 5 == 0)" bit)
    3. If so, return i (the leading i in "i for i in ....")
    4. Return every i that matches 1..3 in a list.

    As a fun aside, try changing the code to:
    Code:
    print( [i*10 for i in range(1,20) if (i % 3 == 0) or (i % 5 == 0)] )
    Note here that the results are i multiplied by 10 (since we have "i * 10" in the beginning).
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    39
    Rep Power
    2
    Ooooh, so the leading "i" is basically the return value.

    Thank you!!
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,889
    Rep Power
    481
    Wonderful. Project Euler #1. Keep going!
    [code]Code tags[/code] are essential for python code and Makefiles!
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    39
    Rep Power
    2
    Code:
    def fib(n):
        a, b = 1, 2
        fib_list = [a]
        for i in range(n):
            a, b = b, a + b
            fib_list.append(a)
        return fib_list
    
    print(sum(i for i in fib(31) if i % 2 == 0))
    How's this for Euler 2? I feel like there should be a better way since I had to manually type in the range for 'fib(31)' until I noticed that 'a' in 'fib_list' was less than four million.
  10. #6
  11. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,889
    Rep Power
    481

    A generator might be a better way.


    Code:
    '''
        >>> for f in fib(2000): print('{:4d}'.format(f))
        ... 
           1
           2
           3
           5
           8
          13
          21
          34
          55
          89
         144
         233
         377
         610
         987
        1597
        >>> 
    '''
    
    def fib(maximum):
        a, b = 1, 2
        while a < maximum:
            yield a
            a, b = b, a + b
    (I'd accept an argument for <= in place of < )
    [code]Code tags[/code] are essential for python code and Makefiles!
  12. #7
  13. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,889
    Rep Power
    481

    "self discovery"


    Matrix multiplication can also generate Fibonacci numbers, and it's a quick way to make large ones. numpy doesn't handle arbitrary precision integers; you'll need to write your own matrix multiplication routine. Don Knuth found other formulas for Fibonacci numbers.
    Code:
    >>> import numpy
    >>> F = numpy.asarray(((0,1),(1,1)))
    >>> F
    array([[0, 1],
           [1, 1]])
    >>> F.dot(F)
    array([[1, 1],
           [1, 2]])
    >>> F.dot(F).dot(F).dot(F).dot(F)
    array([[3, 5],
           [5, 8]])
    >>> F.dot(F).dot(F).dot(F).dot(F).dot(F).dot(F).dot(F)
    array([[13, 21],
           [21, 34]])
    >>> G = F.dot(F).dot(F).dot(F).dot(F)
    >>> G.dot(G)
    array([[34, 55],
           [55, 89]])
    >>>
    [code]Code tags[/code] are essential for python code and Makefiles!
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    39
    Rep Power
    2
    That is so cool. Thank you for showing it
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Posts
    39
    Rep Power
    2
    Hmmm. I don't quite understand 'yield'.

    Is it returning a from the variable below? Or from above? And how does it create a list of numbers?

    Any info would be awesome!!!
  18. #10
  19. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,889
    Rep Power
    481

    in python3...


    It could be the doctest you misunderstood. fib didn't make a list.
    Code:
    >>> fib(3)
    <generator object fib at 0x7f5731a627d0>
    >>> {'__next__', '__iter__'} . intersection(set(dir(fib)))  # fib looks like a function
    set()
    >>> {'__next__', '__iter__'} . intersection(set(dir(fib(8888888))))  # calling fib gives an object that supports iteration.
    {'__iter__', '__next__'}
    Code:
    def fib(maximum):
        a, b = 1, 2
        while a < maximum:
            yield a
            a, b = b, a + b
    
    # we can make a list of Fibonacci numbers.
    print([x for x in fib(22)])  # output is [1, 2, 3, 5, 8, 13, 21]
    [code]Code tags[/code] are essential for python code and Makefiles!

IMN logo majestic logo threadwatch logo seochat tools logo