views:

253

answers:

11

I do not want to use while or for loops, just want to use recursion to return the odd numbers in a given list. Thanks!

+2  A: 
def find_odds(numbers, odds):
    if len(numbers) == 0:
        return
    v = numbers.pop()
    if v % 2 == 1:
        odds.append(v)
    find_odds(numbers, odds)

odds = []
numbers = [1,2,3,4,5,6,7]
find_odds(numbers,odds)
# Now odds has the odd numbers
print odds

Here's a test output of what I get when I run this

[7, 5, 3, 1]

GWW
where is the odds list returned?
The variable odds I edited my answer to help a bit
GWW
It is modified by [reference](http://en.wikipedia.org/wiki/Reference_%28computer_science%29) . So you'd call the function like ``result = []; find_odds(nums, result)``
David Winslow
i tried this out and it is not working for me
It's working perfectly fine for me.
GWW
Please don't do the homework for someone next time.
Kinderchocolate
+1  A: 
odds = []
def findOdds(listOfNumbers):
    if listOfNumbers[0] % 2 == 1:
        odds.append(listOfNumbers[0])
    if len(listOfNumbers) > 1:
        findOdds(listOfNumbers[1:])

findOdds(range(0,10))
print odds
# returns [1,3,5,7,9]
Scott
What about recursion?
thyrgle
This is clearly a superior solution to recursion.
Rafe Kettler
So, when your customer asks you for a web app to run under IIS (a very specific requirement), what do you think they will say when you deliver a Websphere version because it's "clearly a superior solution"? :-)
paxdiablo
In this situation, I would berate the teacher for asking a stupid question. :) It always was a favorite past-time of mine.
Scott
@paxdiablo - different scenario
Scott
@Scott: I take it you don't work out, then.
intuited
-1 for the incorrect regex-based solution. Not only does it not use recursion, but it doesn't come close to working (it returns `1` if you pass it `12`)! If you want to do it with just a single expression, `filter(lambda x: x % 2 == 1, arrayOfNumbers)` is the proper way to do it, not regexes.
Gabe
@Gabe, so right...
Scott
@Gabe, you don't even need the == 1
dcolish
@Scott A regex for numbers (which means str->int->str conversion) does sound like a hammer-nail situation.
Rudi
+2  A: 

Here's another way of doing it which returns the list of odd numbers rather than modifying the list passed in. Very similar to that provided by GWW but I thought I'd add it for completeness.

def find_odds(numbers, odds):
    if len(numbers) == 0:
        return odds

    if numbers[0] % 2 == 1:
        odds.append(numbers[0])

    return find_odds(numbers[1:],odds)

print find_odds([1,2,3,4,5,6,7,8,9],[])

Output is:

[1, 3, 5, 7, 9]
paxdiablo
can you think of a way to do it with only one parameter? thank you
Sure, you could (as one way) create the list to contain _all_ the information and just pass the list. But that's an even worse requirement than your equally arbitrary "must use recursion" one, since it was added after the question was answered. And, to be honest, I'd rather help people out than play "let's change the requirements" games - it's not as if I don't get enough of that in my _real_ job :-)
paxdiablo
+6  A: 
def find_odds(numbers):
  if not numbers:
    return []
  if numbers[0] % 2 == 1:
    return [numbers[0]] + find_odds(numbers[1:])
  return find_odds(numbers[1:])

No extra variables or parameters needed.

Josh Matthews
This is (IMNSHO) the best solution to date since it both minimises the arguments passed and doesn't damage the original list. +1.
paxdiablo
@pax, I have a dumb question to ask...isn't a new list being created everytime `[numbers[0]] + find_odds(numbers[1:])` is executed? :-\ @Josh, +1
st0le
A: 
>>> def fodds(alist, odds=None):
...     if odds is None: odds = []
...     if not alist: return odds
...     x = alist[0] # doesn't destroy the input sequence
...     if x % 2: odds.append(x)
...     return fodds(alist[1:], odds)
...
>>> fodds(range(10)) # only one arg needs to be supplied
[1, 3, 5, 7, 9] # same order as input
>>>

This one avoids the list copying overhead, at the cost of getting the answer backwards and a big increase in the ugliness factor:

>>> def fo(aseq, pos=None, odds=None):
...     if odds is None: odds = []
...     if pos is None: pos = len(aseq) - 1
...     if pos < 0: return odds
...     x = aseq[pos]
...     if x % 2: odds.append(x)
...     return fo(aseq, pos - 1, odds)
...
>>> fo(range(10))
[9, 7, 5, 3, 1]
>>>
John Machin
A: 
def odds(L):
    if L == []: 
        return []
    else:
        if L[0]%2:
            B = odds(L[1:])
            B.append(L[0])
            return B
        else:
            return odds(L[1:])
inspectorG4dget
+3  A: 

Considering the default stack depth limit of 1000 in python, I would really not use recursion for this. I know there are a lot of recursive implementations above so here's a non-recursive one that is doing it the python way:

print filter(lambda x: x % 2, range(0, 10))

And for the sake of completeness; if you really really must use recursion here's my go at it. This is very similar to the version by Josh Matthews.

def rec_foo(list):
    if not list:
        return []
    return ([list[0]] if list[0] % 2 else []) + rec_foo(list[1:])

print rec_foo(range(1, 10))
dcolish
+1: filter seems to be the pythonic way.
Paulo Scardine
A more-pythonic way would be `[x for x in lst if x % 2]`. And please don't use builtin names (list) as parameter names.
Rudi
Well, I'll admit the use of list wasnt the best choice, but hey we all make mistakes. What I'll never understand is how a list comp is more pythonic than a builtin function.
dcolish
+4  A: 
def only_odd(L):
    return L[0:L[0]&1]+only_odd(L[1:]) if L else L

This version is much faster as it avoids making copies of L

def only_odd_no_copy(L, i=0):
    return L[i:i+(L[i]&1)]+only_odd_no_copy(L, i+1) if i<len(L) else []

This one only uses O(log n) stack space

def only_odd_logn(L):
    x=len(L)/2+1
    return L[:L[0]&1] + only_odd2(L[1:x]) + only_odd_logn(L[x:]) if L else L
gnibbler
dcolish
John Machin
Hmm...i must have put that zero there because explicit is better than implicit
gnibbler
@gnibbler, You must have, but I went ahead and removed it while I was profiling your code. +1 I think you had the best answer before mine ;)
aaronasterling
@John, whats not too like. Bitwise ops are awesome and I don't think we see them used enough. Yes that other bit is quite clever too.
dcolish
@gnibbler: ... `if L[i:] else ...` does make a copy of (on average) about half of L, and immediately throws it away. How about a PEP for a composite IS_SLICE_EMPTY or SLICE_LEN opcode :-?
John Machin
@John, You are correct. let me replace it with `i<len(L)`
gnibbler
A: 

Well, there are a bunch of other answers but I think mine's the cleanest:

def odds(L):
   if not L: 
      return []
   return [L[0]] * (L[0] % 2) + odds(L[1:])

Fun exercise but just to reiterate, don't ever do this recursively in practice.

Triptych
@Triptych: mutating the input arg to an empty list is clean?
John Machin
A: 

well since we're all contributing:

def odds(aList):
    from operator import lshift as l
    if aList and not aList[1:]:
        return aList if aList[-1] - l(aList[0]>>1, 1) else list()
    return odds(aList[:len(aList)/3+1]) + odds(aList                                     \
    [len(aList)/3+1:]) if aList else []
TokenMacGuy
+2  A: 

Since it's a party, I just thought I'd chime in with a nice, sensible, Real ProgrammerTM solution. It's written in emacs and inspired by gnibbler's answer. Like his, it uses &1 instead of % 2 (adding 2 into co_consts is pure decadence if 1 is already there) and uses that nifty trick for getting the first element only if it's odd, but shaves some cycles off for a time savings of around 5% (on my machine, running 2.6.5 compiled with GCC 4.4.3 on a linux2 kernel).

from opcode import opmap
import types

opcodes = [opmap['LOAD_FAST'],      0,0,   #    L
           opmap['JUMP_IF_FALSE'],  24,0, 
           opmap['DUP_TOP'],
           opmap['LOAD_CONST'],     0,0,   #    0
           opmap['BINARY_SUBSCR'],  
           opmap['LOAD_CONST'],     1,0,   #    1
           opmap['BINARY_AND'],
           opmap['SLICE+2'],
           opmap['LOAD_GLOBAL'],    0,0,   #    odds
           opmap['LOAD_FAST'],      0,0,
           opmap['LOAD_CONST'],     1,0,
           opmap['SLICE+1'],
           opmap['CALL_FUNCTION'],  1,0,
           opmap['BINARY_ADD'],
           opmap['RETURN_VALUE']]

code_str = ''.join(chr(byte) for byte in opcodes)

code = types.CodeType(1, 1, 4, 0x1 | 0x2 | 0x40, code_str, (0, 1),
                      ('odds',), ('L',), '<nowhere>', 'odds',
                      0, '')

odds = types.FunctionType(code, globals())
aaronasterling
+1, Would love to see the outcome of the OP submitting this for their homework. I added a couple of improved options to my answer
gnibbler
+1 for the wtf look of the prof
Scott