รหัสที่เป็นประโยชน์ซึ่งใช้ลด ()? [ปิด]


123

ใครที่นี่มีโค้ดที่เป็นประโยชน์ซึ่งใช้ฟังก์ชันลด () ใน python หรือไม่? มีรหัสอื่นนอกเหนือจาก + และ * ปกติที่เราเห็นในตัวอย่างหรือไม่?

อ้างถึงFate of reduction () ใน Python 3000โดย GvR


1
from functools import reduceอนุญาตให้โค้ดเดียวกันทำงานบนทั้ง Python 2 และ 3
jfs

คำตอบ:


66

การใช้งานอื่น ๆ ที่ฉันพบนอกเหนือจาก + และ * คือกับและหรือ แต่ตอนนี้เรามีanyและallแทนที่กรณีเหล่านั้น

foldlและfoldrเกิดขึ้นในโครงการมากมาย ...

นี่คือการใช้งานที่น่ารัก:

แบนรายการ

ประตู: เปิดเข้าไป[[1, 2, 3], [4, 5], [6, 7, 8]][1, 2, 3, 4, 5, 6, 7, 8]

reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])

รายการหลักเป็นตัวเลข

ประตู: เปิดเข้าไป[1, 2, 3, 4, 5, 6, 7, 8]12345678

วิธีที่น่าเกลียดและช้า:

int("".join(map(str, [1,2,3,4,5,6,7,8])))

พริตตี้reduceทาง:

reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)

23
สำหรับการแบนรายการฉันชอบรายการ (itertools.chain (* nested_list))
Roberto Bonvallet

13
ผลรวม ([[1, 2, 3], [4, 5], [6, 7, 8]], [])
Gordon Wrigley

3
นอกจากนี้ยังมีประโยชน์สำหรับการดำเนินการในระดับบิต จะเกิดอะไรขึ้นถ้าคุณต้องการใช้บิตหรือตัวเลขจำนวนมากเช่นหากคุณต้องการแปลงแฟล็กจากรายการเป็นบิตมาสก์?
พลวง

6
การทำเกณฑ์มาตรฐานบางอย่างวิธีที่ 'น่าเกลียด' เร็วกว่าสำหรับรายการขนาดใหญ่ timeit.repeat('int("".join(map(str, digit_list)))', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)ใช้เวลา ~ 0.09 วินาทีและtimeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)ใช้เวลา 0.36 วินาที (ช้ากว่าประมาณ 4 เท่า) โดยทั่วไปการคูณด้วย 10 จะมีราคาแพงเมื่อรายการมีขนาดใหญ่ในขณะที่ int ถึง str และการเรียงต่อกันยังคงถูก
dr jimbob

3
จริงอยู่ใช่สำหรับรายการขนาดเล็ก (ขนาด 10) ดังนั้นวิธีลดจะเร็วกว่า 1.3 เท่า อย่างไรก็ตามแม้ในกรณีนี้การหลีกเลี่ยงการลดและการทำลูปแบบง่ายจะยิ่งเร็วขึ้นtimeit.repeat('convert_digit_list_to_int(digit_list)', setup = 'digit_list = [d%10 for d in xrange(1,10)]\ndef convert_digit_list_to_int(digits):\n i = 0\n for d in digits:\n i = 10*i + d\n return i', number=100000)ก็ใช้เวลา 0.06 วินาทีtimeit.repeat('reduce(lambda a,d: 10*a+d, digit_list)', setup = 'digit_list = list(d%10 for d in xrange(1,10))', number=100000)ใช้เวลา 0.12 วินาทีและการแปลงหลักเป็นวิธี str จะใช้เวลา 0.16 วินาที
dr jimbob

51

reduce()สามารถใช้เพื่อค้นหาตัวคูณน้อยที่สุดสำหรับตัวเลข 3 ตัวขึ้นไป :

#!/usr/bin/env python
from fractions import gcd
from functools import reduce

def lcm(*args):
    return reduce(lambda a,b: a * b // gcd(a, b), args)

ตัวอย่าง:

>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560

1
คืออะไรlcmในบรรทัดที่สอง?
beardc

1
@BirdJaguarIV: ตามลิงค์ในคำตอบ lcm()ส่งกลับผลคูณน้อยที่สุดของสองจำนวน
jfs

39

reduce()สามารถใช้เพื่อแก้ไขชื่อที่eval()เป็นจุด (ซึ่งไม่ปลอดภัยที่จะใช้):

>>> import __main__
>>> reduce(getattr, "os.path.abspath".split('.'), __main__)
<function abspath at 0x009AB530>

23

ค้นหาจุดตัดของ N รายการที่กำหนด:

input_list = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

result = reduce(set.intersection, map(set, input_list))

ผลตอบแทน:

result = set([3, 4, 5])

ผ่าน: Python - จุดตัดของสองรายการ



12

ฉันคิดว่าการลดเป็นคำสั่งโง่ ๆ ดังนั้น:

reduce(lambda hold,next:hold+chr(((ord(next.upper())-65)+13)%26+65),'znlorabggbbhfrshy','')

1
ฉันชอบประชดที่นี่ด้วย
Roman

11

การใช้reduceสิ่งที่ฉันพบในโค้ดของฉันเกี่ยวข้องกับสถานการณ์ที่ฉันมีโครงสร้างคลาสสำหรับนิพจน์ตรรกะและฉันจำเป็นต้องแปลงรายการของอ็อบเจ็กต์นิพจน์เหล่านี้เป็นการรวมกันของนิพจน์ ฉันได้มีฟังก์ชั่นในการสร้างร่วมให้ทั้งสองสำนวนดังนั้นฉันเขียนmake_and reduce(make_and,l)(ฉันรู้ว่ารายการไม่ว่างเปล่ามิฉะนั้นจะเป็นเช่นreduce(make_and,l,make_true)นั้น)

นี่คือเหตุผลที่ (บางคน) โปรแกรมเมอร์ที่ใช้งานได้ชอบreduce(หรือฟังก์ชันพับตามที่มักเรียกว่าฟังก์ชันดังกล่าว) มีฟังก์ชั่นไบนารีมักจำนวนมากอยู่แล้วเหมือน+, *, min, max, เรียงต่อกันและในกรณีของฉันและmake_and make_orการมีส่วนreduceช่วยในการยกการดำเนินการเหล่านี้ไปยังรายการ (หรือต้นไม้หรืออะไรก็ได้ที่คุณมีสำหรับฟังก์ชันพับโดยทั่วไป)

แน่นอนว่าหากsumมักใช้อินสแตนซ์บางอย่าง (เช่น) คุณก็ไม่ต้องการเขียนreduceต่อ อย่างไรก็ตามแทนที่จะกำหนดsumด้วย for-loop คุณสามารถกำหนดได้อย่างง่ายดายด้วยreduce.

ความสามารถในการอ่านตามที่ผู้อื่นกล่าวถึงเป็นปัญหาอย่างแท้จริง อย่างไรก็ตามคุณสามารถโต้แย้งได้ว่าเหตุผลเดียวที่ทำให้ผู้คนเห็นว่าreduce"ชัดเจน" น้อยลงเป็นเพราะมันไม่ใช่ฟังก์ชั่นที่หลายคนรู้จักและ / หรือใช้


เพื่อป้องกันรายการว่างคุณสามารถใช้ประโยชน์จากพฤติกรรมการลัดวงจรของandตัวดำเนินการ: L and reduce(make_and, L)หากการส่งคืนรายการว่างนั้นเหมาะสมในกรณีนี้
jfs

9

องค์ประกอบของฟังก์ชัน : หากคุณมีรายการฟังก์ชันที่ต้องการใช้ต่อเนื่องกันเช่น:

color = lambda x: x.replace('brown', 'blue')
speed = lambda x: x.replace('quick', 'slow')
work = lambda x: x.replace('lazy', 'industrious')
fs = [str.lower, color, speed, work, str.title]

จากนั้นคุณสามารถใช้ทั้งหมดติดต่อกันด้วย:

>>> call = lambda s, func: func(s)
>>> s = "The Quick Brown Fox Jumps Over the Lazy Dog"
>>> reduce(call, fs, s)
'The Slow Blue Fox Jumps Over The Industrious Dog'

ในกรณีนี้การเชื่อมโยงวิธีการอาจอ่านได้ง่ายขึ้น แต่บางครั้งก็เป็นไปไม่ได้และองค์ประกอบประเภทนี้อาจอ่านและบำรุงรักษาได้มากกว่าf1(f2(f3(f4(x))))ไวยากรณ์ประเภทหนึ่ง


1
ข้อดีคือคุณสามารถเปลี่ยนรายการฟังก์ชันที่จะใช้ในโค้ดได้
hakanc

9

คุณสามารถแทนที่value = json_obj['a']['b']['c']['d']['e']ด้วย:

value = reduce(dict.__getitem__, 'abcde', json_obj)

หากคุณมีเส้นทางa/b/c/..เป็นรายการอยู่แล้ว ยกตัวอย่างเช่นการเปลี่ยนค่าใน Dict ของ dicts ซ้อนกันโดยใช้รายการในรายการ


7

@ แบลร์คอนราด: คุณสามารถใช้ glob / ลดโดยใช้ sum ได้เช่นกัน:

files = sum([glob.glob(f) for f in args], [])

นี่เป็นรายละเอียดน้อยกว่าตัวอย่างทั้งสองของคุณเป็น Pythonic ที่สมบูรณ์แบบและยังคงเป็นโค้ดเพียงบรรทัดเดียว

ดังนั้นเพื่อตอบคำถามเดิมโดยส่วนตัวฉันพยายามหลีกเลี่ยงการใช้การลดเพราะมันไม่จำเป็นจริงๆและฉันพบว่ามันชัดเจนน้อยกว่าวิธีอื่น ๆ อย่างไรก็ตามบางคนเคยชินกับการลดลงและชอบที่จะแสดงรายการความเข้าใจ (โดยเฉพาะโปรแกรมเมอร์ของ Haskell) แต่ถ้าคุณยังไม่ได้คิดเกี่ยวกับปัญหาในแง่ของการลดคุณอาจไม่จำเป็นต้องกังวลเกี่ยวกับการใช้งาน


2
ทั้งสองอย่างsumและreduceนำไปสู่พฤติกรรมกำลังสอง สามารถทำได้ในเวลาเชิงเส้น: files = chain.from_iterable(imap(iglob, args)). แม้ว่าอาจไม่สำคัญในกรณีนี้เนื่องจากต้องใช้เวลาในการเข้าถึงดิสก์ glob ()
jfs

6

reduce สามารถใช้เพื่อสนับสนุนการค้นหาแอตทริบิวต์ที่ถูกล่ามโซ่:

reduce(getattr, ('request', 'user', 'email'), self)

แน่นอนว่านี่เทียบเท่ากับ

self.request.user.email

แต่จะมีประโยชน์เมื่อรหัสของคุณต้องยอมรับรายการแอตทริบิวต์โดยพลการ

(คุณลักษณะที่ถูกล่ามโซ่ของความยาวโดยพลการเป็นเรื่องปกติเมื่อจัดการกับโมเดล Django)


4

reduceมีประโยชน์เมื่อคุณต้องการค้นหาการรวมกันหรือจุดตัดของลำดับของsetวัตถุที่เหมือนกัน

>>> reduce(operator.or_, ({1}, {1, 2}, {1, 3}))  # union
{1, 2, 3}
>>> reduce(operator.and_, ({1}, {1, 2}, {1, 3}))  # intersection
{1}

(นอกเหนือจากsets จริงตัวอย่างของสิ่งเหล่านี้คือวัตถุ Q ของ Django )

ในทางกลับกันหากคุณกำลังติดต่อกับbools คุณควรใช้anyและall:

>>> any((True, False, True))
True


3

ฉันกำลังเขียนฟังก์ชันเขียนสำหรับภาษาดังนั้นฉันจึงสร้างฟังก์ชันประกอบโดยใช้การลดร่วมกับโอเปอเรเตอร์ใช้ของฉัน

โดยสรุปการเขียนจะนำรายการฟังก์ชันต่างๆมาประกอบเป็นฟังก์ชันเดียว หากฉันมีการดำเนินการที่ซับซ้อนซึ่งใช้เป็นขั้นตอนฉันต้องการรวมทั้งหมดเข้าด้วยกันดังนี้:

complexop = compose(stage4, stage3, stage2, stage1)

ด้วยวิธีนี้ฉันสามารถนำไปใช้กับนิพจน์ดังนี้:

complexop(expression)

และฉันต้องการให้เทียบเท่ากับ:

stage4(stage3(stage2(stage1(expression))))

ตอนนี้ในการสร้างวัตถุภายในของฉันฉันต้องการพูดว่า:

Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x'))))))

(คลาสแลมบ์ดาสร้างฟังก์ชันที่ผู้ใช้กำหนดเองและใช้สร้างแอปพลิเคชันฟังก์ชัน)

ตอนนี้ลดน่าเสียดายที่พับผิดวิธีดังนั้นฉันจึงใช้ประมาณ:

reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')]))

หากต้องการทราบว่าผลิตผลใดที่ลดลงให้ลองใช้สิ่งเหล่านี้ใน REPL:

reduce(lambda x, y: (x, y), range(1, 11))
reduce(lambda x, y: (y, x), reversed(range(1, 11)))


3

สามารถใช้ลดเพื่อรับรายการที่มีองค์ประกอบสูงสุดที่ n

reduce(lambda x,y: x if x[2] > y[2] else y,[[1,2,3,4],[5,2,5,7],[1,6,0,2]])

จะส่งคืน [5, 2, 5, 7] เนื่องจากเป็นรายการที่มีองค์ประกอบสูงสุดที่ 3 +


สูงสุด (lst, key = lambda x: x [2])
aoeu256

3

การลดไม่ จำกัด เฉพาะการดำเนินการสเกลาร์ นอกจากนี้ยังสามารถใช้เพื่อจัดเรียงสิ่งต่างๆลงในถัง (นี่คือสิ่งที่ฉันใช้ลดบ่อยที่สุด)

ลองนึกภาพกรณีที่คุณมีรายการของวัตถุและคุณต้องการจัดระเบียบใหม่ตามลำดับชั้นตามคุณสมบัติที่จัดเก็บไว้ในวัตถุอย่างสม่ำเสมอ ในตัวอย่างต่อไปนี้ฉันสร้างรายการของออบเจ็กต์ข้อมูลเมตาที่เกี่ยวข้องกับบทความในหนังสือพิมพ์ที่เข้ารหัส XML ด้วยarticlesฟังก์ชัน articlesสร้างรายการองค์ประกอบ XML จากนั้นแมปทีละองค์ประกอบสร้างวัตถุที่เก็บข้อมูลที่น่าสนใจเกี่ยวกับองค์ประกอบเหล่านี้ ในส่วนหน้าฉันจะต้องการให้ผู้ใช้เรียกดูบทความตามส่วน / ส่วนย่อย / พาดหัว ดังนั้นฉันจึงใช้reduceเพื่อรับรายการบทความและส่งคืนพจนานุกรมเดียวที่สะท้อนถึงลำดับชั้นของส่วน / ส่วนย่อย / บทความ

from lxml import etree
from Reader import Reader

class IssueReader(Reader):
    def articles(self):
        arts = self.q('//div3')  # inherited ... runs an xpath query against the issue
        subsection = etree.XPath('./ancestor::div2/@type')
        section = etree.XPath('./ancestor::div1/@type')
        header_text = etree.XPath('./head//text()')
        return map(lambda art: {
            'text_id': self.id,
            'path': self.getpath(art)[0],
            'subsection': (subsection(art)[0] or '[none]'),
            'section': (section(art)[0] or '[none]'),
            'headline': (''.join(header_text(art)) or '[none]')
        }, arts)

    def by_section(self):
        arts = self.articles()

        def extract(acc, art):  # acc for accumulator
            section = acc.get(art['section'], False)
            if section:
                subsection = acc.get(art['subsection'], False)
                if subsection:
                    subsection.append(art)
                else:
                    section[art['subsection']] = [art]
            else:
                acc[art['section']] = {art['subsection']: [art]}
            return acc

        return reduce(extract, arts, {})

ฉันให้ทั้งสองฟังก์ชั่นที่นี่เพราะฉันคิดว่ามันแสดงให้เห็นว่าแผนที่และการลดสามารถเสริมซึ่งกันและกันได้อย่างไรเมื่อจัดการกับวัตถุ สิ่งเดียวกันนี้สามารถทำได้ด้วย for loop ... แต่การใช้เวลาอย่างจริงจังกับภาษาที่ใช้งานได้มีแนวโน้มที่จะทำให้ฉันคิดในแง่ของแผนที่และลด

ยังไงก็ตามหากใครมีวิธีตั้งค่าคุณสมบัติที่ดีกว่านี้เหมือนที่ฉันทำอยู่extractซึ่งอาจยังไม่มีผู้ปกครองของทรัพย์สินที่คุณต้องการตั้งค่าโปรดแจ้งให้เราทราบ


3

ไม่แน่ใจว่านี่คือสิ่งที่คุณต้องการหรือไม่ แต่คุณสามารถค้นหาซอร์สโค้ดบน Googleได้

ไปที่ลิงก์เพื่อค้นหา'function: reduce () lang: python'ในการค้นหา Google Code

ในตอนแรกโครงการต่อไปนี้ใช้ reduce()

  • MoinMoin
  • Zope
  • เป็นตัวเลข
  • ScientificPython

ฯลฯ เป็นต้น แต่สิ่งเหล่านี้แทบไม่น่าแปลกใจเนื่องจากเป็นโครงการขนาดใหญ่

ฟังก์ชันการลดสามารถทำได้โดยใช้ฟังก์ชันการเรียกซ้ำซึ่งฉันเดาว่า Guido คิดว่าชัดเจนกว่า

ปรับปรุง:

เนื่องจากการค้นหาโค้ดของ Google หยุดให้บริการในวันที่ 15 ม.ค. 2555 นอกเหนือจากการเปลี่ยนกลับเป็นการค้นหาปกติของ Google แล้วยังมีสิ่งที่เรียกว่าCode Snippets Collectionที่ดูมีแนวโน้ม มีการกล่าวถึงแหล่งข้อมูลอื่น ๆ ในคำตอบคำถามนี้ (ปิด) การเปลี่ยน Google Code Search? .

อัปเดต 2 (29 พฤษภาคม 2560):

แหล่งที่ดีสำหรับตัวอย่างหลาม (ในรหัสเปิดแหล่งที่มา) เป็นเครื่องมือค้นหา Nullege


1
"การทำงานของการลดสามารถทำได้โดยใช้ฟังก์ชันการเรียกซ้ำ" ... หรือforวนซ้ำ
Jason Orendorff

2
นอกจากนี้การค้นหาลด () ให้โครงการที่กำหนดฟังก์ชันลดภายในโค้ดของพวกเขา คุณควรค้นหา lang: python "ลด (" เพื่อค้นหาการใช้งานจริงของฟังก์ชันในตัว
Seun Osewa

@Seun Osewa: แม้แต่การค้นหาlang:python "reduce("ก็จะพบคำจำกัดความreduceขึ้นอยู่กับรูปแบบการเข้ารหัสซอร์สโค้ด
martineau

2
import os

files = [
    # full filenames
    "var/log/apache/errors.log",
    "home/kane/images/avatars/crusader.png",
    "home/jane/documents/diary.txt",
    "home/kane/images/selfie.jpg",
    "var/log/abc.txt",
    "home/kane/.vimrc",
    "home/kane/images/avatars/paladin.png",
]

# unfolding of plain filiname list to file-tree
fs_tree = ({}, # dict of folders
           []) # list of files
for full_name in files:
    path, fn = os.path.split(full_name)
    reduce(
        # this fucction walks deep into path
        # and creates placeholders for subfolders
        lambda d, k: d[0].setdefault(k,         # walk deep
                                     ({}, [])), # or create subfolder storage
        path.split(os.path.sep),
        fs_tree
    )[1].append(fn)

print fs_tree
#({'home': (
#    {'jane': (
#        {'documents': (
#           {},
#           ['diary.txt']
#        )},
#        []
#    ),
#    'kane': (
#       {'images': (
#          {'avatars': (
#             {},
#             ['crusader.png',
#             'paladin.png']
#          )},
#          ['selfie.jpg']
#       )},
#       ['.vimrc']
#    )},
#    []
#  ),
#  'var': (
#     {'log': (
#         {'apache': (
#            {},
#            ['errors.log']
#         )},
#         ['abc.txt']
#     )},
#     [])
#},
#[])

1
คุณช่วยเพิ่มคำอธิบายเล็กน้อยเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่ได้ไหม มิฉะนั้นประโยชน์จะไม่ชัดเจนเลย
Zoran Pavlovic



1

ฉันมีการใช้ python แบบเก่าของpipegrepที่ใช้การลดและโมดูล glob เพื่อสร้างรายการไฟล์ที่จะประมวลผล:

files = []
files.extend(reduce(lambda x, y: x + y, map(glob.glob, args)))

ฉันพบว่ามันมีประโยชน์ในตอนนั้น แต่มันไม่จำเป็นจริงๆเพราะสิ่งที่คล้ายกันนั้นดีพอ ๆ กันและอาจอ่านได้มากกว่า

files = []
for f in args:
    files.extend(glob.glob(f))

ความเข้าใจเกี่ยวกับรายการเป็นอย่างไร? นี้ดูเหมือนว่าโปรแกรมที่สมบูรณ์แบบสำหรับมัน files = [glob.glob(f) for f in args]
steveha

อันที่จริงแล้ว @steveha ตัวอย่างของคุณจะส่งผลให้รายการของ globs ที่ขยายออกมาแทนที่จะเป็นรายการรวมของรายการทั้งหมดที่ตรงกับ globs แต่คุณสามารถใช้ list compleion + sum เป็น @ [Eli Courtwright] (# 16198 ) ชี้ให้เห็น.
Blair Conrad

1
โอเคคุณพูดถูกต้องขออภัยด้วย ฉันยังไม่ชอบการรวมขยาย / ลด / แลมบ์ดา / แผนที่มากนัก! ฉันขอแนะนำให้นำเข้าitertoolsโดยใช้flatten()สูตรจากdocs.python.org/library/itertools.htmlจากนั้นจึงเขียน: files = flatten(glob.glob(f) for f in args) (และคราวนี้ฉันทดสอบโค้ดก่อนโพสต์และฉันรู้ว่ามันทำงานได้ถูกต้อง)
steveha

files = chain.from_iterable(imap(iglob, args))ที่chain, imapจากitertoolsโมดูลและglob.iglobจะเป็นประโยชน์ถ้ารูปแบบจากargsอาจผลผลิตไฟล์จากหลายไดเรกทอรี
jfs

1

สมมติว่ามีข้อมูลสถิติรายปีที่จัดเก็บรายการเคาน์เตอร์ เราต้องการหาค่า MIN / MAX ในแต่ละเดือนในปีต่างๆ ตัวอย่างเช่นในเดือนมกราคมจะเป็นวันที่ 10 และสำหรับเดือนกุมภาพันธ์จะเป็น 15 เราจำเป็นต้องเก็บผลลัพธ์ไว้ในตัวนับใหม่

from collections import Counter

stat2011 = Counter({"January": 12, "February": 20, "March": 50, "April": 70, "May": 15,
           "June": 35, "July": 30, "August": 15, "September": 20, "October": 60,
           "November": 13, "December": 50})

stat2012 = Counter({"January": 36, "February": 15, "March": 50, "April": 10, "May": 90,
           "June": 25, "July": 35, "August": 15, "September": 20, "October": 30,
           "November": 10, "December": 25})

stat2013 = Counter({"January": 10, "February": 60, "March": 90, "April": 10, "May": 80,
           "June": 50, "July": 30, "August": 15, "September": 20, "October": 75,
           "November": 60, "December": 15})

stat_list = [stat2011, stat2012, stat2013]

print reduce(lambda x, y: x & y, stat_list)     # MIN
print reduce(lambda x, y: x | y, stat_list)     # MAX

1

ฉันมีวัตถุที่แสดงถึงช่วงเวลาที่ทับซ้อนกัน (genomic exons) และกำหนดจุดตัดใหม่โดยใช้__and__:

class Exon:
    def __init__(self):
        ...
    def __and__(self,other):
        ...
        length = self.length + other.length  # (e.g.)
        return self.__class__(...length,...)

จากนั้นเมื่อฉันมีคอลเลกชันของพวกมัน (เช่นในยีนเดียวกัน) ฉันก็ใช้

intersection = reduce(lambda x,y: x&y, exons)

1

ฉันเพิ่งพบการใช้งานที่มีประโยชน์reduce: สตริงแยกโดยไม่ต้องถอดตัวคั่น รหัสทั้งหมดมาจากบล็อกการพูดแบบเป็นโปรแกรม นี่คือรหัส:

reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem == "\n" else acc + [elem], re.split("(\n)", "a\nb\nc\n"), [])

นี่คือผลลัพธ์:

['a\n', 'b\n', 'c\n', '']

โปรดทราบว่ามันจัดการกับขอบกรณีที่คำตอบยอดนิยมใน SO ไม่ได้ สำหรับคำอธิบายเชิงลึกเพิ่มเติมฉันกำลังเปลี่ยนเส้นทางคุณไปยังบล็อกโพสต์ต้นฉบับ


0

ใช้การลด () เพื่อดูว่ารายการวันที่ติดต่อกันหรือไม่:

from datetime import date, timedelta


def checked(d1, d2):
    """
    We assume the date list is sorted.
    If d2 & d1 are different by 1, everything up to d2 is consecutive, so d2
    can advance to the next reduction.
    If d2 & d1 are not different by 1, returning d1 - 1 for the next reduction
    will guarantee the result produced by reduce() to be something other than
    the last date in the sorted date list.

    Definition 1: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider consecutive
    Definition 2: 1/1/14, 1/2/14, 1/2/14, 1/3/14 is consider not consecutive

    """
    #if (d2 - d1).days == 1 or (d2 - d1).days == 0:  # for Definition 1
    if (d2 - d1).days == 1:                          # for Definition 2
        return d2
    else:
        return d1 + timedelta(days=-1)

# datelist = [date(2014, 1, 1), date(2014, 1, 3),
#             date(2013, 12, 31), date(2013, 12, 30)]

# datelist = [date(2014, 2, 19), date(2014, 2, 19), date(2014, 2, 20),
#             date(2014, 2, 21), date(2014, 2, 22)]

datelist = [date(2014, 2, 19), date(2014, 2, 21),
            date(2014, 2, 22), date(2014, 2, 20)]

datelist.sort()

if datelist[-1] == reduce(checked, datelist):
    print "dates are consecutive"
else:
    print "dates are not consecutive"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.