Có ai ở đây có bất kỳ mã hữu ích nào sử dụng hàm less () trong python không? Có mã nào khác ngoài + và * thông thường mà chúng ta thấy trong các ví dụ không?
Tham khảo Số phận giảm () trong Python 3000 của GvR
Có ai ở đây có bất kỳ mã hữu ích nào sử dụng hàm less () trong python không? Có mã nào khác ngoài + và * thông thường mà chúng ta thấy trong các ví dụ không?
Tham khảo Số phận giảm () trong Python 3000 của GvR
Câu trả lời:
Các ứng dụng khác mà tôi đã tìm thấy cho nó ngoài + và * là với và và, nhưng bây giờ chúng tôi có any
và all
để thay thế các trường hợp đó.
foldl
và foldr
xuất hiện trong Đề án rất nhiều ...
Đây là một số cách sử dụng dễ thương:
Làm phẳng một danh sách
Mục tiêu: biến [[1, 2, 3], [4, 5], [6, 7, 8]]
thành [1, 2, 3, 4, 5, 6, 7, 8]
.
reduce(list.__add__, [[1, 2, 3], [4, 5], [6, 7, 8]], [])
Danh sách các chữ số cho một số
Mục tiêu: biến [1, 2, 3, 4, 5, 6, 7, 8]
thành 12345678
.
Cách xấu xí, chậm chạp:
int("".join(map(str, [1,2,3,4,5,6,7,8])))
reduce
Cách khá :
reduce(lambda a,d: 10*a+d, [1,2,3,4,5,6,7,8], 0)
timeit.repeat('int("".join(map(str, digit_list)))', setup = 'digit_list = list(d%10 for d in xrange(1,1000))', number=1000)
mất ~ 0,09 giây trong khi 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)
mất 0,36 giây (chậm hơn khoảng 4 lần). Về cơ bản nhân với 10 trở nên đắt đỏ khi danh sách trở nên lớn, trong khi int đến str và phép nối vẫn rẻ.
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)
mất 0,06 giây, 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)
mất 0,12 giây và chuyển đổi chữ số sang phương thức str mất 0,16 giây.
reduce()
có thể được sử dụng để tìm bội số chung nhỏ nhất cho 3 số trở lên :
#!/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)
Thí dụ:
>>> lcm(100, 23, 98)
112700
>>> lcm(*range(1, 20))
232792560
lcm
trong dòng thứ hai?
Tìm giao điểm của N danh sách đã cho:
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))
trả về:
result = set([3, 4, 5])
thông qua: Python - Giao lộ của hai danh sách
Việc sử dụng reduce
mà tôi tìm thấy trong mã của mình liên quan đến tình huống trong đó tôi có một số cấu trúc lớp cho biểu thức logic và tôi cần chuyển đổi một danh sách các đối tượng biểu thức này thành một biểu thức kết hợp. Tôi đã có một chức năng make_and
để tạo ra một kết hợp cho hai biểu thức, vì vậy tôi đã viết reduce(make_and,l)
. (Tôi biết danh sách này không có sản phẩm nào; nếu không nó sẽ giống nhưreduce(make_and,l,make_true)
.)
Đây chính xác là lý do mà (một số) lập trình viên chức năng thích reduce
(hoặc gấp các hàm, vì các hàm như vậy thường được gọi). Thường đã có nhiều chức năng như nhị phân +
, *
, min
, max
, nối, và trong trường hợp của tôi, make_and
và make_or
. Có mộtreduce
làm cho nó trở nên tầm thường để nâng các hoạt động này lên danh sách (hoặc cây hoặc bất cứ thứ gì bạn có, cho các hàm gấp nói chung).
Tất nhiên, nếu một số cảnh báo nhất định (như sum
) thường được sử dụng, thì bạn không muốn tiếp tục viết reduce
. Tuy nhiên, thay vì xác định sum
với một số vòng lặp for, bạn có thể dễ dàng xác định nó với reduce
.
Khả năng đọc, như được đề cập bởi những người khác, thực sự là một vấn đề. Tuy nhiên, bạn có thể tranh luận rằng lý do duy nhất khiến mọi người thấy reduce
ít "rõ ràng" hơn vì đó không phải là chức năng mà nhiều người biết và / hoặc sử dụng.
and
nhà điều hành: L and reduce(make_and, L)
nếu trả về danh sách trống là phù hợp trong trường hợp này
Thành phần chức năng : Nếu bạn đã có một danh sách các chức năng mà bạn muốn áp dụng liên tiếp, chẳng hạn như:
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]
Sau đó, bạn có thể áp dụng tất cả chúng liên tiếp với:
>>> 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'
Trong trường hợp này, chuỗi phương thức có thể dễ đọc hơn. Nhưng đôi khi điều đó là không thể, và loại sáng tác này có thể dễ đọc và dễ bảo trì hơn một f1(f2(f3(f4(x))))
loại cú pháp.
Bạn có thể thay thế value = json_obj['a']['b']['c']['d']['e']
bằng:
value = reduce(dict.__getitem__, 'abcde', json_obj)
Nếu bạn đã có đường dẫn a/b/c/..
như một danh sách. Ví dụ: Thay đổi giá trị trong dict của các dicts lồng nhau bằng cách sử dụng các mục trong danh sách .
@Blair Conrad: Bạn cũng có thể triển khai toàn cầu / giảm bằng cách sử dụng tổng, như vậy:
files = sum([glob.glob(f) for f in args], [])
Điều này ít dài dòng hơn một trong hai ví dụ của bạn, hoàn toàn là Pythonic và vẫn chỉ là một dòng mã.
Vì vậy, để trả lời câu hỏi ban đầu, cá nhân tôi cố gắng tránh sử dụng giảm vì nó không bao giờ thực sự cần thiết và tôi thấy nó không rõ ràng hơn các phương pháp khác. Tuy nhiên, một số người đã quen với việc giảm bớt và thích sử dụng nó để liệt kê những hiểu biết (đặc biệt là các lập trình viên Haskell). Nhưng nếu bạn chưa nghĩ về vấn đề giảm thiểu, có lẽ bạn không cần phải lo lắng về việc sử dụng nó.
sum
và reduce
dẫn đến hành vi bậc hai. Nó có thể được thực hiện trong thời gian tuyến tính : files = chain.from_iterable(imap(iglob, args))
. Mặc dù trong trường hợp này có lẽ không có vấn đề gì do phải mất thời gian để global () truy cập vào đĩa.
reduce
có thể được sử dụng để hỗ trợ tra cứu thuộc tính chuỗi:
reduce(getattr, ('request', 'user', 'email'), self)
Tất nhiên, điều này tương đương với
self.request.user.email
nhưng nó hữu ích khi mã của bạn cần chấp nhận một danh sách các thuộc tính tùy ý.
(Các thuộc tính xích có độ dài tùy ý là phổ biến khi xử lý các mô hình Django.)
reduce
là hữu ích khi bạn cần tìm liên kết hoặc giao điểm của một chuỗi các set
đối tượng giống như.
>>> reduce(operator.or_, ({1}, {1, 2}, {1, 3})) # union
{1, 2, 3}
>>> reduce(operator.and_, ({1}, {1, 2}, {1, 3})) # intersection
{1}
(Ngoài set
s thực tế , một ví dụ trong số này là các đối tượng Q của Django .)
Mặt khác, nếu bạn đang làm việc với bool
s, bạn nên sử dụng any
và all
:
>>> any((True, False, True))
True
Sau khi lấy mã của mình, có vẻ như điều duy nhất tôi đã sử dụng giảm là tính toán giai thừa:
reduce(operator.mul, xrange(1, x+1) or (1,))
Tôi đang viết một hàm soạn thảo cho một ngôn ngữ, vì vậy tôi xây dựng hàm tổng hợp bằng cách sử dụng hàm giảm cùng với toán tử ứng dụng của tôi.
Tóm lại, compose lấy một danh sách các hàm để soạn thành một hàm duy nhất. Nếu tôi có một thao tác phức tạp được áp dụng theo từng giai đoạn, tôi muốn kết hợp tất cả lại với nhau như vậy:
complexop = compose(stage4, stage3, stage2, stage1)
Bằng cách này, sau đó tôi có thể áp dụng nó cho một biểu thức như vậy:
complexop(expression)
Và tôi muốn nó tương đương với:
stage4(stage3(stage2(stage1(expression))))
Bây giờ, để xây dựng các đối tượng nội bộ của tôi, tôi muốn nó nói:
Lambda([Symbol('x')], Apply(stage4, Apply(stage3, Apply(stage2, Apply(stage1, Symbol('x'))))))
(Lớp Lambda xây dựng một hàm do người dùng định nghĩa và Áp dụng xây dựng một ứng dụng hàm.)
Bây giờ, giảm, không may, gấp sai cách, vì vậy tôi sử dụng, khoảng:
reduce(lambda x,y: Apply(y, x), reversed(args + [Symbol('x')]))
Để tìm ra những gì giảm sản xuất, hãy thử những điều này trong 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)
để tạo tất cả các kết hợp chức năng có thể để kiểm tra hiệu suất.
giảm có thể được sử dụng để có được danh sách với phần tử thứ n tối đa
reduce(lambda x,y: x if x[2] > y[2] else y,[[1,2,3,4],[5,2,5,7],[1,6,0,2]])
sẽ trả về [5, 2, 5, 7] vì đây là danh sách có phần tử thứ 3 tối đa +
Giảm không giới hạn trong các hoạt động vô hướng; nó cũng có thể được sử dụng để sắp xếp mọi thứ vào xô. (Đây là những gì tôi sử dụng giảm cho thường xuyên nhất).
Hãy tưởng tượng một trường hợp trong đó bạn có một danh sách các đối tượng và bạn muốn tổ chức lại nó theo thứ bậc dựa trên các thuộc tính được lưu trữ thẳng trong đối tượng. Trong ví dụ sau, tôi tạo một danh sách các đối tượng siêu dữ liệu liên quan đến các bài viết trong một tờ báo được mã hóa XML có articles
chức năng. articles
tạo một danh sách các phần tử XML và sau đó lần lượt ánh xạ qua chúng, tạo ra các đối tượng chứa một số thông tin thú vị về chúng. Ở mặt trước, tôi sẽ muốn cho phép người dùng duyệt các bài viết theo phần / tiểu mục / tiêu đề. Vì vậy, tôi sử dụng reduce
để lấy danh sách các bài báo và trả về một từ điển duy nhất phản ánh thứ bậc của phần / tiểu mục / bài viết.
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, {})
Tôi cung cấp cả hai chức năng ở đây vì tôi nghĩ nó cho thấy cách ánh xạ và thu nhỏ có thể bổ sung cho nhau một cách độc đáo khi tiếp xúc với các đối tượng. Điều tương tự có thể đã được thực hiện với một vòng lặp for, ... nhưng dành một chút thời gian nghiêm túc với một ngôn ngữ chức năng có xu hướng khiến tôi suy nghĩ về bản đồ và giảm bớt.
Nhân tiện, nếu có ai có cách tốt hơn để đặt các thuộc tính như tôi đang làm extract
, nơi cha mẹ của tài sản bạn muốn đặt có thể chưa tồn tại, vui lòng cho tôi biết.
Không chắc chắn nếu đây là những gì bạn đang theo đuổi nhưng bạn có thể tìm kiếm mã nguồn trên Google .
Theo liên kết để tìm kiếm trên 'function: less () lang: python' trên tìm kiếm Google Code
Thoạt nhìn các dự án sau sử dụng reduce()
vv vv nhưng sau đó hầu như không đáng ngạc nhiên vì chúng là những dự án lớn.
Chức năng giảm có thể được thực hiện bằng cách sử dụng đệ quy hàm mà tôi đoán Guido nghĩ rõ ràng hơn.
Cập nhật:
Vì Tìm kiếm mã của Google đã bị ngừng vào ngày 15 tháng 1 năm 2012, bên cạnh việc trở lại các tìm kiếm thông thường của Google, có một thứ gọi là Bộ sưu tập mã đoạn có vẻ đầy hứa hẹn. Một số tài nguyên khác được đề cập trong câu trả lời câu hỏi (đóng) này Thay thế cho Tìm kiếm mã của Google? .
Cập nhật 2 (29 tháng 5 năm 2017):
Một nguồn tốt cho các ví dụ Python (trong mã nguồn mở) là công cụ tìm kiếm Nulitic .
for
vòng lặp.
lang:python "reduce("
cũng sẽ tìm thấy các định nghĩa reduce
tùy thuộc vào phong cách mã hóa mã nguồn.
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']
# )},
# [])
#},
#[])
Tôi đã sử dụng reduce
để ghép một danh sách các vectơ tìm kiếm PostgreSQL với ||
toán tử trong 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)
Tôi có một triển khai Python cũ của pipegrep sử dụng mô đun rút gọn và toàn cầu để xây dựng danh sách các tệp cần xử lý:
files = []
files.extend(reduce(lambda x, y: x + y, map(glob.glob, args)))
Tôi thấy nó tiện dụng vào thời điểm đó, nhưng nó thực sự không cần thiết, vì một cái gì đó tương tự cũng tốt như vậy, và có lẽ dễ đọc hơn
files = []
for f in args:
files.extend(glob.glob(f))
files = [glob.glob(f) for f in args]
itertools
, sử dụng flatten()
công thức từ docs.python.org/library/itertools.html , và sau đó viết: files = flatten(glob.glob(f) for f in args)
(Và thời gian này, tôi đã thử nghiệm mã trước khi đăng nó, và Ta biết công việc này một cách chính xác.)
files = chain.from_iterable(imap(iglob, args))
trong đó chain
, imap
là từ itertools
mô-đun và glob.iglob
rất hữu ích nếu một mẫu từ args
có thể mang lại các tệp từ một số thư mục.
Giả sử có một số dữ liệu thống kê hàng năm được lưu trữ một danh sách các Bộ đếm. Chúng tôi muốn tìm các giá trị MIN / MAX mỗi tháng trong các năm khác nhau. Ví dụ: trong tháng 1 sẽ là 10. Và cho tháng 2 sẽ là 15. Chúng ta cần lưu trữ kết quả trong một Counter mới.
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
Tôi có các đối tượng đại diện cho một số loại khoảng thời gian chồng chéo (exon genomic) và xác định lại giao điểm của chúng bằng cách sử dụng __and__
:
class Exon:
def __init__(self):
...
def __and__(self,other):
...
length = self.length + other.length # (e.g.)
return self.__class__(...length,...)
Sau đó, khi tôi có một bộ sưu tập chúng (ví dụ, trong cùng một gen), tôi sử dụng
intersection = reduce(lambda x,y: x&y, exons)
Tôi chỉ tìm thấy cách sử dụng hữu ích của reduce
: tách chuỗi mà không xóa dấu phân cách . Mã này hoàn toàn từ blog Nói theo lập trình. Đây là mã:
reduce(lambda acc, elem: acc[:-1] + [acc[-1] + elem] if elem == "\n" else acc + [elem], re.split("(\n)", "a\nb\nc\n"), [])
Đây là kết quả:
['a\n', 'b\n', 'c\n', '']
Lưu ý rằng nó xử lý các trường hợp cạnh mà câu trả lời phổ biến trong SO không. Để giải thích sâu hơn, tôi đang chuyển hướng bạn đến bài viết blog ban đầu.
Sử dụng less () để tìm hiểu xem danh sách ngày có liên tiếp không:
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"
from functools import reduce
cho phép cùng một mã hoạt động trên cả Python 2 và 3.