0

I am in the middle of writing a large piece of code and I want to shorten a length or expression. Let's say we have a list, something like:

farm = ["cow","cow","cow", "hen","hen","hen", "fox","fox","fox", "hen","hen", "hen"]
lookup = ["cow","hen"]

I am supposed to check whether there are three consecutive elements of lookfor in farm list.

One way is to do:

for i in range (0,len(farm) - 2):
  if ((farm[i] == farm[i+1] == farm[i+2] == lookup[0])
     or (farm[i] == farm[i+1] == farm[i+2] == lookup[1])):
    # do something

Now if the number of elements in lookup is small, it can be written in the above way. However, if it is too long the code looks cumbersome and is harder to maintain. Is there a more concise way of writing the code, perhaps in list comprehension format - so that I do not have to manually write to look for all the elements of lookup?

zondo
  • 19,901
  • 8
  • 44
  • 83
motiur
  • 1,640
  • 9
  • 33
  • 61
  • 1
    Disagree with the close. The OP already solved the "presence of a sliced list" problem - they're asking for a Pythonic way to check for the presence of any of an _arbitrary number of_ target sublists. The linked question doesn't even mention that. – Tim Peters Apr 02 '17 at 02:05
  • @TimPeters - I thought they were interested in reducing the `farm[i] == farm[i+1]...`. The additional original should solve the other challenge as well. – TigerhawkT3 Apr 02 '17 at 02:09
  • @motiur, you're looking for the `any()` builtin function, like `if any( for target in lookfor)` – Tim Peters Apr 02 '17 at 02:09
  • @TigerhawkT3, no, they explicitly said "Now if the number of elements in `lookfor` is small , it can written in the above way .However, if it is too long the code looks cumbersome ...". Their question was entirely about what to do when `lookfor` "is too long". – Tim Peters Apr 02 '17 at 02:13
  • @TimPeters - Yes, I was incorrect; sorry about that. Should be all fixed now. – TigerhawkT3 Apr 02 '17 at 02:14
  • Or maybe not fixed enough, I guess. Could've sworn I'd added all relevant originals. – TigerhawkT3 Apr 02 '17 at 02:23

2 Answers2

2

try this

gr = [(k,len(list(ns))) for k,ns in itertools.groupby(farm)]
for k in lookup:
    if (k,3) in gr:
        print k

will check for exact three consecutive keys. For at least three, you can filter the groups by size and check whether each entry is in the lookup.

karakfa
  • 66,216
  • 7
  • 41
  • 56
1

Untested, but something "like this" ;-) should work. any() is a natural way to process an arbitrary number of ors, and all() for arbitrary number of ands.

if any(farm[i] == farm[i+1] == farm[i+2] == target for i in range(len(farm) - 2)
       for target in lookup):
    # do something

If you need i

This variant will give you the matching i value, and is very much like your original code:

for i in range (0,len(farm) - 2):
   if any(farm[i] == farm[i+1] == farm[i+2] == target for target in lookup):
       print(i)    
Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • If I `print( farm[i], farm[i+1], farm[i+2])` I get `fox,fox,fox` - I was expecting `cow` and `hen` only. – motiur Apr 02 '17 at 02:34
  • Sorry, I can't guess what you mean. In the code I gave, `i` is local to the comprehension, and would have no effect on any variable of the same name outside the comprehension. If you _need_ the value of `i` where it matches, then that's a new requirement that wasn't mentioned in the original question. – Tim Peters Apr 02 '17 at 02:40
  • See edit for an obvious way to capture the `i` value. – Tim Peters Apr 02 '17 at 02:43