Search code examples
pythoniteratorany

getting iterator from if any()


I have this simple function:

keys = ['snmt1/metadata/table1/ref_table1_20190324124365.csv', 'snmt1/metadata/table2/table2_ref_20190324124365.csv', 'snmt1/metadata/table3/table3_20190324124365.csv']


def better_func(keys):
  for item in keys:
    split_key = item.split("/")
    filename = str(split_key[-1])
    prefixes = ['strm','ref','trunc']
    if any(x in filename for x in prefixes):
      location = filename.find(x)
      if location == 0:
        print True
      else:
        print "another false"
    else:
      print False

What I need is the value of "x" so that I can return the index of it with the .find() function. This code above doesn't work because it is telling me:

NameError: global name 'x' is not defined

Which I understand but how can I access "x" like I can normally do in a for loop?

for x in my_list:
    print x

Solution

  • Instead of

    if any(x in filename for x in prefixes):
        # do stuff with x
    

    you can do:

    x = next((p for p in prefixes if p in filename), None)
    if x:
        # do stuff with x
    

    This creates an generator, and takes the next value from it -that is, the first value. The second argument to None is a sentinel value: if the iterator raises a StopIteration, rather than passing this exception, then None is returned, and bound to x.

    This does not look so useful here, but it really comes in a handy when you want the first element of a sequence that satisfies a condition, and a fallback operation if there is no such element:

    elt = next((x for x in range(10) if x > 5), None)
    if elt is not None:
        print("{} satisfies the condition".format(elt))
    else:
        print("No such element found")
    

    Note that generators are iterators too, so you can directly call next on them. With an iterable like a list, a dict or anything else, you'd need to call iter first. For instance, this is useful to take an arbitrary value from a dictionary:

    value = next(iter(d.values()))