Finding lowest value within a nested list?

2020-03-30 04:12发布

问题:

Im trying to write a function that takes a list and can print the lowest integer that is within that list. Now i'm trying to figure out what to do where this works with nested lists that if the lowest number is within one of those nested lists then overall it will print that number. My code is here:

def listMin():
list2 = [3,4,[2,99,8],7]

for i in range (len(list2)):
    if type(list2[i]) == type([]):



        y=min(i)
        list2.append(y)
        print "hello"
    if len(list2)== 0:
        return None
    else:


        x= min(list2)
        print x


listMin()

while this seems like it should print the number 2 it doesnt and just gives me an error once it reaches the nested list saying:

TypeError: 'int' object is not iterable

ive tried multiple things but i'm having a hard time as to why this sort of thing isn't working.

回答1:

In general, you could flatten your list of lists and search for min in the flattened list. There are many recipes for flattening. Here is one that I took from here.

import collections

def flatten(iterable):
    for el in iterable:
        if isinstance(el, collections.Iterable) and not isinstance(el, str): 
            yield from flatten(el)
        else:
            yield el

list2 = [3,4,[2,99,8],7]

print(list(flatten(list2)))
# [3, 4, 2, 99, 8, 7]
print(min(flatten(list2)))   
# 2

This will work on multiple nested list as well, e.g.:

list2 = [3,4,[2,99,8,[-1,-2]],7]

print(list(flatten(list2)))
# [3, 4, 2, 99, 8, -1, -2, 7]
print(min(flatten(list2)))  
# -2 


回答2:

Nesting One Deep

In your example, the list is nested only one deep. If this is the case in general, then try:

>>> list2 = [3,4,[2,99,8],7]
>>> min(x if isinstance(x, int) else min(x) for x in list2)
2

Nesting of Arbitrary Depth

If deeper nesting is allowed, define this recursive function:

>>> def rmin(lst): return min(x if isinstance(x, int) else rmin(x) for x in lst)
... 

In operation:

>>> rmin(list2)
2

Or, with deeper nesting:

>>> list3 = [3,4,[[2,99],8],7]
>>> rmin(list3)
2
>>> list4 = [3, 4, [[2, [99, 1]], 8], 7]
>>> rmin(list4)
1

How it works

The function rmin consists of the single line:

return min(x if isinstance(x, int) else rmin(x) for x in lst)

As you can see, this is a list comprehension that looks at every value x of the list lst.

Let's divide the argument of min into two parts. The first is:

x if isinstance(x, int) else rmin(x)

This returns x if x is an integer. Otherwise, it calls rmin on x. In the latter case, rmin recursively looks at every value in x and returns the minimum.

The second part of the argument of min is:

for x in lst

This is just the usual for a list comprehension. It extracts each value in lst in turn and assigns it to x.



回答3:

The problem is caused by the line

y=min(i)

where i is an integer but not a list. You probably want y = min(list2[i]).

Note that while you have appended this y back to the original list, the loop would not reach the newly added element, since i will only range up to the original length of the list.

With some simple Python idioms, your original idea can be expressed in a more readable way as follows:

def listMin():
    lst = [3,4,[2,99,8],7]
    for x in lst:
        if type(x) == list:
            lst.append(min(x))
    print min(lst)


listMin()


回答4:

When I needed to do something similar, I wrote following:

import copy

def nestedMin(list_):
  target_list = copy.deepcopy(list_)  # to keep original list unchanged
  for index in range (len(target_list)):
    if type (target_list[index]) is list:
      target_list[index] = nestedMin(target_list[index])

  return min(target_list)

I know that it is not very efficient, keeps doing deepcopy; but it's readable and it does the job :)

Example:

list1 = [2,3,[4, -5, [7, -20]]]
print nestedMin(list1) # prints -20
print list1  # prints [2, 3, [4, -5, [7, -20]]]