วิธีใช้ตัวดำเนินการเชิงตรรกะกับองค์ประกอบทั้งหมดในรายการหลาม


93

ฉันมีรายการบูลีนใน python ฉันต้องการ AND (หรือหรือหรือไม่) และรับผลลัพธ์ รหัสต่อไปนี้ใช้งานได้ แต่ไม่ใช่ pythonic มาก

def apply_and(alist):
 if len(alist) > 1:
     return alist[0] and apply_and(alist[1:])
 else:
     return alist[0]

ข้อเสนอแนะใด ๆ เกี่ยวกับวิธีทำให้ pythonic ชื่นชมมากขึ้น

คำตอบ:


181

ตรรกะandในทุกองค์ประกอบในa_list:

all(a_list)

ตรรกะorในทุกองค์ประกอบในa_list:

any(a_list)

หากคุณรู้สึกสร้างสรรค์คุณสามารถทำสิ่งต่อไปนี้ได้

import operator
def my_all(a_list):
  return reduce(operator.and_, a_list, True)

def my_any(a_list):
  return reduce(operator.or_, a_list, False)

โปรดทราบว่าสิ่งเหล่านี้ไม่ได้รับการประเมินในการลัดวงจรในขณะที่บิวท์อินคือ ;-)

อีกวิธีที่ตลก:

def my_all_v2(a_list):
  return len(filter(None,a_list)) == len(a_list)

def my_any_v2(a_list):
  return len(filter(None,a_list)) > 0

และอีกอย่าง:

def my_all_v3(a_list):
  for i in a_list:
    if not i:
      return False
  return True

def my_any_v3(a_list):
  for i in a_list:
    if i:
      return True
  return False

และเราสามารถไปได้ทั้งวัน แต่ใช่วิธี pythonic คือการใช้allและany:-)

อย่างไรก็ตาม Python ไม่ได้กำจัดการเรียกซ้ำหางดังนั้นอย่าพยายามแปลรหัส LISP โดยตรง ;-)


8
operator.and_ คือบิตและตัวดำเนินการ & ไม่ใช่ตรรกะและ.
Ants Aasma

1
โชคดีที่ True และ False (ตามที่ op ต้องการ) จะถูกโยนเป็น 1 และ 0 ตามลำดับดังนั้นตัวดำเนินการระดับบิตจึงทำงานเป็นตรรกะ ^ _ ^
fortran

6
อธิบายเวอร์ชันซ้ำซ้อนจำนวนมาก แต่ไม่ได้ระบุไวยากรณ์สำหรับคำตอบที่ถูกต้องจริง
jwg

2
ไม่เห็นด้วยสิ่งที่คุณต้องการอยู่ในคำถามที่พบบ่อย: stackoverflow.com/privileges/vote-down
fortran

2
โปรดทราบว่าreduce()อยู่ในfunctoolsตั้งแต่ Python 3.0
Duncan WP

33

ANDING และ ORing เป็นเรื่องง่าย:

>>> some_list = [True] * 100
# OR
>>> any(some_list)
True
#AND
>>> all(some_list)
True
>>> some_list[0] = False
>>> any(some_list)
True
>>> all(some_list)
False

การสังเกตก็ค่อนข้างง่ายเช่นกัน:

>>> [not x for x in some_list]
[True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]

แน่นอนว่าคุณจะใช้ผลลัพธ์เหล่านั้นอย่างไรอาจต้องใช้ทฤษฎีบทของ DeMorgan ที่น่าสนใจ


4
หากคุณต้องการการลัดวงจรของตัวแปรที่ไม่ใช่เพียงแค่ใช้นิพจน์ตัวสร้าง: all(not x for x in some_list)(แต่นั่นก็เหมือนกับnot any(some_list)(เป็นการแสดงออกที่เป็นธรรมชาติใช่มั้ย?))
u0b34a0f6ae

16

ลดสามารถทำได้:

reduce(lambda a,b: a and b, alist, True)

ดังที่ Fortran กล่าวไว้ทั้งหมดเป็นวิธีที่รวบรัดที่สุดที่จะทำ แต่ลดคำตอบสำหรับคำถามทั่วไป "จะใช้ตัวดำเนินการเชิงตรรกะกับองค์ประกอบทั้งหมดในรายการหลามได้อย่างไร"


4
ลดไม่หายไป AFAIK มันถูกย้ายไปยังโมดูล functools จากตำแหน่งก่อนหน้าในเนมสเปซทั่วโลก
Eli Bendersky

1
@eliben: ทำไมต้องพูดถึง Python 3 ในอนาคต? ลดยังมีอยู่ reduceอยู่functools.reduce ใน Python 3
u0b34a0f6ae

หากคุณลบ, Trueคำตอบนี้จะเป็นเพียงคำตอบเดียวที่เทียบเท่ากับรหัสของคำถามสำหรับรายการที่ไม่ใช่บูลีน
Thomas Ahle

10

สำนวนสำหรับการดำเนินการดังกล่าวคือการใช้reduceฟังก์ชัน (global ใน Python 2.X ในโมดูลfunctoolsใน Python 3.X) ด้วยตัวดำเนินการไบนารีที่เหมาะสมซึ่งนำมาจากoperatorโมดูลหรือเข้ารหัสอย่างชัดเจน ในกรณีของคุณก็คือoperator.and_

reduce(operator.and_, [True, True, False])

4

นี่คือวิธีอื่น:

def my_and(a_list):
    return not (False in a_list)

def my_or(a_list):
    return True in a_list

AND เมื่อองค์ประกอบทั้งหมดจะคืนค่า True หากองค์ประกอบทั้งหมดเป็น True ดังนั้นจึงไม่มี False ในรายการ ORing คล้ายกัน แต่ควรส่งคืน True หากมีค่า True อย่างน้อยหนึ่งค่าอยู่ในรายการ


0

ดังที่คำตอบอื่น ๆ แสดงให้เห็นมีหลายวิธีในการทำงานนี้ให้สำเร็จ นี่คืออีกวิธีหนึ่งที่ใช้ฟังก์ชันจากไลบรารีมาตรฐาน:

from functools import partial

apply_and = all
apply_or = any
apply_not = partial(map, lambda x: not x)

if __name__ == "__main__":
    ls = [True, True, False, True, False, True]
    print "Original: ", ls
    print "and: ", apply_and(ls)
    print "or: ", apply_or(ls)
    print "not: ", apply_not(ls)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.