2015-06-15 21 views
14

Sadece Python ile başlıyorum.Liste bir boole içeriyorsa, bir tamsayı dizininden liste nasıl alınır?

1 önce liste bir boolean True nesnesi içeriyorsa, 1 tamsayı indisi nasıl elde edilir?

>>> lst = [True, False, 1, 3] 
>>> lst.index(1) 
0 
>>> lst.index(True) 
0 
>>> lst.index(0) 
1 

Python 0 index yöntemin argüman True olarak False olarak ve 1 gördüğü düşünüyorum. Nasıl tamsayı 1 (yani 2) dizinini alabilirim?

Ayrıca boolean nesne listesinde bu şekilde tedavi arkasındaki mantık veya mantık nedir? Çözümlerden görüldüğü gibi, bu kadar basit değil.

+4

Bu soruna "Burada yapmak istediklerim" den yaklaşmak daha iyi olurdu "Yapmak istemediğim şey ...". Örneğin. ne * özellikle * bir şey için bir liste aramak istediğinizi yapmaya çalışıyorsunuz, ama aradığınız şeyle eşit olan şeyleri atlamak mı istiyorsunuz? Durumun en muhtemel gerçekleri ya gerçekten istediğinizi 'list.index (1)' sürprizinize rağmen '0' döndürmek ya da gerçekten bu aramayı yapmanız gereken bir duruma sokmamaktır. . – Hurkyl

+6

Python geliştiricisiyim, ama aynı listedeki booleanlarla birlikte tamsayıları depolamak biraz garip değil mi? Arabaları ve meyveleri birarada görüyorum ... –

cevap

13

documentation

Listeleri (benzerlik kesin derecesine uygulamaya göre değişebilir bir yere) tipik olarak homojen öğeleri depolamak koleksiyonları için kullanılabilir kesilebilir dizileri olduğunu söyler.

Sen listelerinde heterojen veri depolamak olmamalıdır. list.index uygulanması sadece Py_EQ (== operatörü) kullanılarak bir karşılaştırma yapar. True ve False tamsayılar 1 ve (sonuçta the bool class is a subclass of int) sırasıyla 0, değerlerini çünkü sizin durumda karşılaştırma truthy değerini döndürmesi.

Ancak böyle (jeneratörden ilk değeri elde etmek) jeneratör ifade ve built-in next function kullanabilirsiniz: Burada

In [4]: next(i for i, x in enumerate(lst) if not isinstance(x, bool) and x == 1) 
Out[4]: 2 

biz kontrol x için x karşılaştıran önce boolörneğidir ise 1.

next durumda, 0 davranışını taklit etmek için (yeniden) (ValueError yükseltmek için arzu edilebilir, StopIteration yükseltmek göz önünde bulundurun).

hepsi bir fonksiyon içerisine Ambalaj:

def index_same_type(it, val): 
    gen = (i for i, x in enumerate(it) if type(x) is type(val) and x == val) 
    try: 
     return next(gen) 
    except StopIteration: 
     raise ValueError('{!r} is not in iterable'.format(val)) from None 

Bazı örnekler: Burada

In [34]: index_same_type(lst, 1) 
Out[34]: 2 

In [35]: index_same_type(lst, True) 
Out[35]: 0 

In [37]: index_same_type(lst, 42) 
ValueError: 42 is not in iterable 
5

çok basit naif bir liner çözüm map ve zip kullanıyor:

>>> zip(map(type, lst), lst).index((int, 1)) 
2 

Burada her elemanın türünü haritalandırıyoruz ve türleri sıkıştırarak yeni bir liste oluşturuyoruz elemanları ile ve (type, value) dizinini isteyin.Burada temelde aynı şeyi yapmak

>>> from itertools import imap, izip 
>>> def index(xs, x): 
...  it = (i for i, (t, e) in enumerate(izip(imap(type, xs), xs)) if (t, e) == x) 
...  try: 
...    return next(it) 
...  except StopIteration: 
...    raise ValueError(x) 
... 
>>> index(lst, (int, 1)) 
2 

ancak bellek/Alan verimi açısından çok bize maliyeti değil iteratif şekilde: Burada

Ve

aynı tekniği kullanarak genel bir iteratif bir çözümdür. Yukarıdaki ifadenin bir yineleyicisiyiz, bunun yerine imap ve izip'u kullanarak ve eşzamanlamadan sonraki değeri döndüren bir özel dizin işlevi veya eşleşme yoksa ValueError'u yükseltiyoruz.

0

Bunu deneyin.

for i, j in enumerate([True, False, 1, 3]): 
    if not isinstance(j, bool) and j == 1: 
     print i 

Çıktı:

2 
7

Booleans Python tam sayılardır ve sadece herhangi bir tamsayı gibi kullanabilirsiniz neden şudur:

>>> 1 + True 
2 
>>> [1][False] 
1 

[bu demek değildir yapmalısınız :)]

Bu,gerçeğinden kaynaklanmaktadır, int'un bir alt sınıfıdır ve hemen hemen her zaman bir boolean, 0 veya 1 gibi davranır (dizgiye verildiğinde hariç - "False" ve "True" alırsınız). İşte

istediğini elde edebilirsiniz nasıl bir daha akıllıca olur (ancak, yukarıdaki bilgileri göz önünde tutarak size mantığını yeniden düşünmeye çalışın):

>>> class force_int(int): 
...  def __eq__(self, other): 
...   return int(self) == other and not isinstance(other, bool) 
... 
>>> force_int(1) == True 
False 
>>> lst.index(force_int(1)) 
2 

Bu kod için kullanılır int 'ın yöntemini yeniden tanımlayan booleanları yok saymak için index yöntemindeki öğeleri karşılaştırın.