4

I have a list of strings, e.g.

lst = ['2', '\n', '4', '\n', '\n']

I'm trying to determine the index point of the last string element that is not '\n'. In the above example the index point would be 2 as '4' is the last element whose value is not '\n'.

I can find the first occurance of '\n' easy etc:

lst.index('\n') 

Is there a way to find the last occurance of an element that IS NOT of a particular string char?

jpp
  • 159,742
  • 34
  • 281
  • 339
arsenal88
  • 1,040
  • 2
  • 15
  • 32
  • 1
    easiest is probably just to loop through the list backwards until you find an element that matches your criteria – SuperStew Jan 21 '19 at 15:59
  • 1
    I dont think this is a duplication... I would suggest that you create a function and use the `for idx, el in enumerate(lst):` ignore `/n` and store the last string you find in a variable, finally return the variable. – Hans Daigle Jan 21 '19 at 16:03
  • @interjay, have reopened since I agree this isn't a duplicate (there may be a better one but it hasn't been proposed yet). – jpp Jan 21 '19 at 16:16
  • @interjay, Because I couldn't deduce the answer to *this* question by reading *that* post; looks like I'm not the only one either. There may be a better duplicate target around, but I couldn't find it. – jpp Jan 21 '19 at 16:51
  • @jpp That doesn't answer my question. What's different about the two questions? – interjay Jan 21 '19 at 16:53
  • @jpp Who's arguing? I was asking a simple question that but you're refusing to answer for some reason. I have no idea why you reopened. – interjay Jan 21 '19 at 16:57
  • @jpp That doesn't answer my question. What's different about the two questions? Your copy/pasted comment explains nothing about what difference you think there is between the two questions. Why act passive-aggressively instead of having a civil discussion? – interjay Jan 21 '19 at 17:07
  • @jpp Your "explanation" can be copy/pasted on any question that was reopened. It doesn't explain anything. I asked for explanation related to *this* question. Your refusal makes me think that there isn't one but you won't admit to your mistake. – interjay Jan 21 '19 at 17:11

1 Answers1

5

You can use next with enumerate, then subtract the result from the length of your list:

lst = ['2', '\n', '4', '\n', '\n']
idx = len(lst) - next(i for i, val in enumerate(reversed(lst), 1) if val != '\n')  # 2

Or, as proposed by @Chris_Rands, iterate backwards via a range that counts down:

idx = next(i for i in range(len(lst)-1, -1, -1) if lst[i] != '\n')  # 2
jpp
  • 159,742
  • 34
  • 281
  • 339
  • 1
    beat me to it. +1 for the `reversed`. I would add a default value in case the `next` exhausts its iterator. – Ma0 Jan 21 '19 at 16:02
  • 1
    At this point I'm thinking if a naive loop is not going to be more efficient? or even just more readable? – DeepSpace Jan 21 '19 at 16:02
  • @DeepSpace, I don't think it can be avoided. Of course here the advisable option is to use `reversed` to work backwards rather than forwards. – jpp Jan 21 '19 at 16:03
  • @jpp Yeah I guess you are correct, I was thinking about some way to avoid `len(lst)` but I guess you can't. Sometimes I wonder why `list` does not implement `rindex` like `str` does – DeepSpace Jan 21 '19 at 16:06
  • 1
    `next(i for i in range(len(lst)-1, 0,-1) if lst[i] != '\n')` ? – Chris_Rands Jan 21 '19 at 16:10
  • The following seems to be quite fast too `lst.index(''.join(lst).strip().rsplit('\n', 1)[-1])`. Actually a bit faster on my machine. I am not sure how it scales though. And it does assume that there is a `\n` between every valid item. – Ma0 Jan 21 '19 at 16:17
  • the stop should be -1 actually `range(len(lst)-1, -1,-1)` – Chris_Rands Jan 21 '19 at 16:17
  • The @Chris_Rands solution is best – jamylak Jan 22 '19 at 01:46
  • @jamylak, I'm on the fence. *Usually* it's better to `enumerate` than to cycle a `range` and index the list in each iteration. But in this case you get to avoid a `reversed` call. So I think each have their merits. – jpp Jan 22 '19 at 01:53
  • @jpp You're right that usually it's better, i think this is rare case where going back to an old school `range` is better, avoids the subtraction :P – jamylak Jan 22 '19 at 03:03
  • If the condition is not found, the next will launch a StopIteration exception because it cannot iterate an empty list. You can add a default value if you want to avoid this : `idx = next((i for i in range(len(lst)-1, -1, -1) if lst[i] != '\n'), None)` – mxdbld Nov 14 '22 at 20:05