14

I was trying to write an answer to this question and was quite surprised to find out that there is no find method for lists, lists have only the index method (strings have find and index).

Can anyone tell me the rationale behind that? Why strings have both?

Community
  • 1
  • 1
ChessMaster
  • 529
  • 1
  • 4
  • 12
  • This question is about the list equivalent of this: `"112131".find("1213") => 1` ie `[1,1,2,1,3,1].find([1,2,1,3]) => 1` -- If you want to do this *in linear time* you need to implement one of the string matching algorithms yourself, which is not that easy. – Jochen Ritzel Oct 03 '10 at 16:26

3 Answers3

7

I don't know why or maybe is buried in some PEP somewhere, but i do know 2 very basic "find" method for lists, and they are array.index() and the in operator. You can always make use of these 2 to find your items. (Also, re module, etc)

ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 2
    `index` method and `in` operator can look for single items in lists (Somebody please tell me if I can call them atomic). OP wants to know if he can find whether a list is a sub-list of another with items appearing in the same order. – dheerosaur Oct 03 '10 at 07:35
  • But the basic principle behind is also iteration through the list, whether its nested or not, and finding them with these operators. OP is also free to develop own method/classes/generators etc for that. – ghostdog74 Oct 03 '10 at 07:37
  • The standard `find` method for arrays is to search for a single item. Nobody would be surprised to learn that an array implementation doesn't do substring searches. – Glenn Maynard Oct 03 '10 at 07:37
  • 1
    @Glenn Maynard: With Python's otherwise very thorough treatment of lists, and its insistence on strings being treated similar to lists, I do find it surprising. – Tim Yates Oct 03 '10 at 16:52
4

I think the rationale for not having separate 'find' and 'index' methods is they're not different enough. Both would return the same thing in the case the sought item exists in the list (this is true of the two string methods); they differ in case the sought item is not in the list/string; however you can trivially build either one of find/index from the other. If you're coming from other languages, it may seem bad manners to raise and catch exceptions for a non-error condition that you could easily test for, but in Python, it's often considered more pythonic to shoot first and ask questions later, er, to use exception handling instead of tests like this (example: Better to 'try' something and catch the exception or test if its possible first to avoid an exception?).

I don't think it's a good idea to build 'find' out of 'index' and 'in', like

if foo in my_list:
   foo_index = my_list.index(foo)
else:
    foo_index = -1 # or do whatever else you want

because both in and index will require an O(n) pass over the list.

Better to build 'find' out of 'index' and try/catch, like:

try:
    foo_index = my_list.index(foo)
catch ValueError:
    foo_index = -1 # or do whatever else you want

Now, as to why list was built this way (with only index), and string was built the other way (with separate index and find)... I can't say.

Community
  • 1
  • 1
metamatt
  • 13,809
  • 7
  • 46
  • 56
2

The "find" method for lists is index.

I do consider the inconsistency between string.find and list.index to be unfortunate, both in name and behavior: string.find returns -1 when no match is found, where list.index raises ValueError. This could have been designed more consistently. The only irreconcilable difference between these operations is that string.find searches for a string of items, where list.index searches for exactly one item (which, alone, doesn't justify using different names).

Glenn Maynard
  • 55,829
  • 10
  • 121
  • 131
  • 5
    try `"asdfasdf".index('z')` next time your in an REPL. – aaronasterling Oct 03 '10 at 07:50
  • 1
    @AaronMcSmooth: It highlights the absurdity of the oft-parroted "one obvious way to do something", when they can't even hold to it for core string methods. – Glenn Maynard Oct 03 '10 at 08:18
  • 6
    but the point of my example is that they _do_ hold to it. `list` and `string` both have an `index` method that behaves exactly the same. it's just that `string` adds a `find` method on top of that. I'm not sure why they don't do it for `list` as well but there is no equivalence between `list.index` and `string.find`. – aaronasterling Oct 03 '10 at 08:33
  • @AaronMcSmooth: The inconsistency is just shifted a little, with the underlying cause being the redundant search functions. (`getattr` handles this properly, allowing both a sentinel or an exception depending on what's needed.) – Glenn Maynard Oct 03 '10 at 09:22
  • 2
    @AaronMcSmooth, although `string` and `list` both have an `.index()` method, it doesn't do quite the same thing. For strings it will find substring, but a sublist of a list -- which to me is another example of the inconsistency. – martineau Oct 03 '10 at 12:38
  • @marineau, that's a great point. I suppose I'm wrong. not the first time by a mile – aaronasterling Oct 03 '10 at 12:39
  • @AaronMcSmooth. How can you see and respond to my comment before I even hit the 'Add Comment' button? It really throws me off and now I can't fix the typos in it. – martineau Oct 03 '10 at 12:43