reduce ()를 사용하는 유용한 코드? [닫은]


123

여기 누구든지 파이썬에서 reduce () 함수를 사용하는 유용한 코드가 있습니까? 예제에서 볼 수있는 일반적인 + 및 * 이외의 코드가 있습니까?

GvR의 Python 3000에서 reduce ()의 운명을 참조하십시오.


1
from functools import reduce동일한 코드가 Python 2와 3 모두에서 작동하도록 허용합니다.
jfs

답변:


66

내가 + 외에 그것을 발견하고 * 한 다른 용도와와와 나 있었지만, 지금 우리가 가지고 anyall그 사례를 대체 할 수 있습니다.

foldl그리고 foldrScheme에 많이 등장합니다 ...

다음은 몇 가지 귀여운 사용법입니다.

목록 병합

목표 : 설정 [[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
목록을 평면화하려면 list (itertools.chain (* nested_list))를 선호합니다
Roberto Bonvallet

13
sum ([[1, 2, 3], [4, 5], [6, 7, 8]], [])
Gordon Wrigley

3
비트 연산에도 유용합니다. 예를 들어 목록에서 비트 마스크로 플래그를 변환해야하는 경우와 같이 비트 단위 또는 여러 숫자를 취하려면 어떻게해야합니까?
Antimony

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 to str 및 concatenation은 저렴합니다.
jimbob 박사는

3
물론, 작은 목록 (크기 10)의 경우에는 reduce 방법이 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 초가 걸립니다.
박사 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>


12

축소는 어리석은 명령이라고 생각합니다. 그 후:

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

1
나는 여기 아이러니 같은
로마

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일부 루프와 함께, 당신은 할 수 있습니다 그냥 간단하게 그것을 정의한다 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 2015 년


7

@Blair Conrad : 다음과 같이 sum을 사용하여 glob / reduce를 구현할 수도 있습니다.

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

이것은 두 가지 예제 중 하나보다 덜 장황하고 완벽하게 Pythonic이며 여전히 한 줄의 코드입니다.

그래서 원래의 질문에 답하기 위해 저는 정말로 필요하지 않고 다른 접근 방식보다 덜 명확하기 때문에 감소를 사용하지 않으려 고 개인적으로 노력합니다. 그러나 어떤 사람들은 축소에 익숙해지고 이해력을 나열하는 것을 선호합니다 (특히 Haskell 프로그래머). 그러나 축소 측면에서 문제에 대해 아직 생각하고 있지 않다면 사용에 대해 걱정할 필요가 없습니다.


2
모두 sumreduce차 동작이 발생할. 선형 시간으로 수행 할 수 있습니다 files = chain.from_iterable(imap(iglob, args)).. 이 경우 glob ()이 디스크에 액세스하는 데 걸리는 시간 때문에 중요하지 않을 수 있습니다.
jfs

6

reduce 연결 속성 조회를 지원하는 데 사용할 수 있습니다.

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

물론 이것은

self.request.user.email

그러나 코드가 임의의 속성 목록을 허용해야 할 때 유용합니다.

(임의의 길이로 연결된 속성은 Django 모델을 다룰 때 일반적입니다.)


4

reduceset유사 객체 시퀀스의 합집합 또는 교차를 찾아야 할 때 유용 합니다.

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

(실제 sets를 제외하고 이들의 예는 Django의 Q 객체입니다. 입니다.)

반면에 bools를 다루는 경우 anyall다음 을 사용해야합니다 .

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


3

저는 언어에 대한 compose 함수를 작성 중이므로 apply 연산자와 함께 reduce를 사용하여 구성된 함수를 구성합니다.

간단히 말해 compose는 단일 함수로 구성 할 함수 목록을 사용합니다. 단계적으로 적용되는 복잡한 작업이 있으면 다음과 같이 모두 합치고 싶습니다.

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'))))))

(Lambda 클래스는 사용자 정의 함수를 빌드하고 Apply는 함수 애플리케이션을 빌드합니다.)

이제, 불행히도 잘못된 방식으로 접을 수 있으므로 대략적으로 다음과 같이 사용했습니다.

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)))

성능 테스트를 위해 가능한 모든 기능 조합compose = lambda *func: lambda arg: reduce(lambda x, f: f(x), reversed(funcs), arg)생성하는
jfs

3

reduce는 최대 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]])

최대 3 번째 요소가있는 목록이므로 [5, 2, 5, 7]을 반환합니다.


max (lst, key = lambda x : x [2])
aoeu256

3

Reduce는 스칼라 연산에만 국한되지 않습니다. 사물을 버킷으로 분류하는데도 사용할 수 있습니다. (이것은 내가 가장 자주 사용하는 것입니다).

객체 목록이 있고 객체에 단순하게 저장된 속성을 기반으로 계층 적으로 재구성하려는 경우를 상상해보십시오. 다음 예에서는 articles함수를 사용하여 XML 인코딩 신문의 기사와 관련된 메타 데이터 개체 목록을 생성 합니다. articlesXML 요소 목록을 생성 한 다음 하나씩 매핑하여 흥미로운 정보를 담고있는 객체를 생성합니다. 프런트 엔드에서는 사용자가 섹션 / 하위 섹션 / 헤드 라인별로 기사를 탐색 할 수 있도록하고 싶습니다. 그래서 저는 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, {})

객체를 다룰 때 map과 reduce가 서로를 잘 보완 할 수있는 방법을 보여주기 때문에 여기에 두 기능을 모두 제공합니다. for 루프로도 똑같은 일을 할 수 있었지만 ... 기능적 언어에 대해 진지한 시간을 보내면 맵 측면에서 생각하고 줄이는 경향이 있습니다.

그건 그렇고, 내가에서하는 것처럼 속성을 설정하는 더 좋은 방법이 있다면 설정 extract하려는 속성의 부모가 아직 존재하지 않을 수도 있습니다. 알려주세요.


3

이것이 당신이 추구 하는 것인지 확실하지 않지만 Google에서 소스 코드를 검색 할 수 있습니다. .

'function : reduce () lang : python' 에 대한 검색 링크를 따르십시오.Google 코드 검색 에

언뜻보기에 다음 프로젝트 사용 reduce()

  • 모인 모인
  • 조프
  • 숫자
  • ScientificPython

등등. 그러나 이것들은 거대한 프로젝트이기 때문에 놀라운 일이 아닙니다.

reduce의 기능은 Guido가 더 명확하다고 생각했던 함수 재귀를 사용하여 수행 할 수 있습니다.

최신 정보:

Google의 코드 검색이 2012 년 1 월 15 일에 중단되었으므로 일반 Google 검색으로 돌아가는 것 외에도 유망 해 보이는 코드 스 니펫 컬렉션 이라는 것이 있습니다. 이 (닫힌) 질문에 대한 답변에는 다른 많은 리소스가 언급되어 있습니다. Google 코드 검색을 대체합니까? .

업데이트 2 (2017 년 5 월 29 일) :

Python 예제 (오픈 소스 코드)에 대한 좋은 소스는 Nullege 검색 엔진 입니다.


1
"recursion 함수는 함수 재귀를 사용하여 수행 할 수 있습니다 for. "... 또는 루프.
Jason Orendorff 2009

2
또한 reduce ()를 검색하면 코드 내에서 reduce 함수를 정의하는 프로젝트가 생성됩니다. 당신은 LANG을 검색한다 : 파이썬은 "(감소"내장 기능의 실제 용도 찾을 수 있습니다.
세운 Osewa을

@Seun Osewa : 검색해도 소스 코드 코딩 스타일 lang:python "reduce("reduce따라 정의를 찾을 수 있습니다.
martineau 2011

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 2014 년

2
def dump(fname,iterable):
  with open(fname,'w') as f:
    reduce(lambda x, y: f.write(unicode(y,'utf-8')), iterable)

2

reduce PostgreSQL 검색 벡터 목록을|| sqlalchemy-searchable 의 연산자 와 연결하는 데 사용 했습니다 .

vectors = (self.column_vector(getattr(self.table.c, column_name))
           for column_name in self.indexed_columns)
concatenated = reduce(lambda x, y: x.op('||')(y), vectors)
compiled = concatenated.compile(self.conn)

1

reduce 및 glob 모듈을 사용하여 처리 할 파일 목록을 작성 하는 pipegrep 의 이전 Python 구현이 있습니다.

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, 귀하의 예제는 glob과 일치하는 모든 항목의 단순 목록이 아닌 확장 glob 목록의 목록을 생성하지만 @ [Eli Courtwright] (# 16198)와 같이 목록 이해 + 합계를 사용할 수 있습니다. ) 지적.
Blair Conrad

1
좋아요, 맞습니다. 죄송합니다. 나는 여전히 확장 / 축소 / 람다 / 맵의 조합이별로 마음에 들지 않습니다! docs.python.org/library/itertools.htmlitertoolsflatten()레시피를 사용 하여을 가져 와서 다음과 같이 작성 하는 것이 좋습니다 . 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 값을 찾고 싶습니다. 예를 들어, 1 월의 경우 10이되고 2 월의 경우 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

나는 일종의 겹치는 간격 (게놈 엑손)을 나타내는 객체를 가지고 있으며 __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: 구분 기호를 제거하지 않고 분할 문자열 . 코드는 전적으로 Programatically Speaking 블로그에서 가져온 것입니다. 코드는 다음과 같습니다.

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

reduce ()를 사용하여 날짜 목록이 연속적인지 확인합니다.

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.