เป็นไปได้ไหมที่จะมีหลายคำสั่งในนิพจน์ python lambda?


112

ฉันเป็นมือใหม่หลามที่พยายามทำสิ่งต่อไปนี้:

ฉันมีรายชื่อรายการ:

lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]

ฉันต้องการแมป lst ในรายการอื่นที่มีเพียงตัวเลขที่เล็กที่สุดเป็นอันดับสองจากแต่ละรายการย่อย ดังนั้นผลลัพธ์ควรเป็น:

[345, 465, 333]

ตัวอย่างเช่นหากฉันสนใจเพียงตัวเลขที่น้อยที่สุดฉันสามารถทำได้:

map(lambda x: min(x),lst)

ฉันหวังว่าฉันจะทำได้:

map(lambda x: sort(x)[1],lst)

แต่การเรียงลำดับไม่เชื่อมโยงกัน (ส่งกลับไม่มี)

สิ่งนี้ไม่ได้รับอนุญาต:

map(lambda x: sort(x); x[1],lst) #hence the multiple statement question

มีวิธีดำเนินการกับ map ใน python แต่ไม่ได้กำหนดฟังก์ชันที่มีชื่อหรือไม่? (เป็นเรื่องง่ายด้วยบล็อกที่ไม่ระบุชื่อในทับทิมเป็นต้น)


แน่นอนว่าน่าจะเป็นไปได้.. อาจจะเป็นเวอร์ชั่นใหม่ ...
ZEE

1
คุณไม่สามารถเรียกใช้งานคำสั่งได้ แต่คุณสามารถเรียกใช้ฟังก์ชันในฟังก์ชันแลมบ์ดาได้ดังนั้นการแฮ็กสกปรกที่ไม่เป็นอันตรายlambda x: sort(x) OR x[1]จะทำงานได้ที่นี่หรือจะประเมินอาร์กิวเมนต์แรก (ค่าที่ส่งคืนไม่มี) เป็นบูล (=> เท็จ) และในกรณีนั้นหรือ ส่งคืนอาร์กิวเมนต์ที่สอง แต่อย่างที่คำตอบบอกว่าควรหลีกเลี่ยงแลมด้าดีกว่า
สูงสุด

คำตอบ:


136

มีคำตอบที่แตกต่างกันหลายประการที่ฉันสามารถให้ได้ที่นี่ตั้งแต่คำถามเฉพาะของคุณไปจนถึงข้อกังวลทั่วไป ดังนั้นจากที่เฉพาะเจาะจงที่สุดไปจนถึงทั่วไปส่วนใหญ่:

ถามคุณสามารถใส่คำสั่งหลาย ๆ คำลงในแลมบ์ดาได้หรือไม่?

ตอบไม่ได้ แต่จริงๆแล้วคุณไม่จำเป็นต้องใช้แลมด้า คุณสามารถใส่คำสั่งdefแทนได้ กล่าวคือ:

def second_lowest(l):
    l.sort()
    return l[1]

map(second_lowest, lst)

ถามคุณสามารถหารายการที่ต่ำที่สุดเป็นอันดับสองจากแลมบ์ดาโดยการจัดเรียงรายการได้หรือไม่?

ตอบใช่ ดังที่คำตอบของ alexชี้ให้เห็นsorted()เป็นเวอร์ชันของการจัดเรียงที่สร้างรายการใหม่แทนที่จะจัดเรียงในสถานที่และสามารถผูกมัดได้ โปรดทราบว่านี่อาจเป็นสิ่งที่คุณควรใช้ซึ่งเป็นแนวทางปฏิบัติที่ไม่ดีสำหรับแผนที่ของคุณที่จะมีผลข้างเคียงกับรายการเดิม

ถาม:ฉันจะได้รับรายการต่ำสุดอันดับสองจากแต่ละรายการในลำดับรายการได้อย่างไร?

A. sorted(l)[1]ไม่ใช่วิธีที่ดีที่สุดสำหรับสิ่งนี้ มีความซับซ้อน O (N log (N)) ในขณะที่มีโซลูชัน O (n) อยู่ สิ่งนี้สามารถพบได้ในโมดูล heapq

>>> import  heapq
>>> l = [5,2,6,8,3,5]
>>> heapq.nsmallest(l, 2)
[2, 3]

ดังนั้นเพียงใช้:

map(lambda x: heapq.nsmallest(x,2)[1],  list_of_lists)

นอกจากนี้ยังถือว่าชัดเจนกว่าในการใช้ความเข้าใจในรายการซึ่งหลีกเลี่ยงแลมบ์ดาโดยสิ้นเชิง:

[heapq.nsmallest(x,2)[1] for x in list_of_lists]

3
ฉันคิดว่าคุณไม่ถูกต้องเกี่ยวกับโซลูชัน O (n) ที่พบในโมดูล heapq สิ่งที่คุณทำมีเพียงฮีปจัดเรียงรายการซึ่งก็คือ O (n log n) จากนั้นค้นหาองค์ประกอบที่เล็กที่สุด
avpx

8
เอกสารประกอบ ( docs.python.org/2/library/heapq.html#heapq.nsmarest ) เตือนว่าการใช้ heapq.nsmarest () อาจมีประสิทธิภาพน้อยกว่าการใช้ sorted () ดังนั้นการวัดเท่านั้นที่สามารถบอกได้ว่าโซลูชันใดคือ เร็วที่สุดในกรณีของคุณ heapq.nsmarest () มีความซับซ้อนของ O (k * log (n) + n) ฉันคิดว่าด้วย n ความยาวของรายการและ k จำนวนรายการที่เล็กที่สุดที่คุณต้องการแยก O (n) เพื่อเพิ่มรายการและ k ครั้ง O (log (n)) เพื่อป๊อป k รายการ ดีกว่า O (n * log (n)) โดยเฉพาะอย่างยิ่งสำหรับ k ขนาดเล็ก
Vortexfive

2
@Vortexfive และสำหรับค่าคงที่k(ตามที่นี่กับ 'วินาทีต่ำสุด') O(k*log(n)+n)ทำให้ง่ายขึ้นO(n)
ดันแคน

5
ในทางเทคนิคแล้วคุณไม่จำเป็นต้องใช้แลมด้าสำหรับหนึ่งสมุทร แต่มันสะดวกกว่าอย่างแน่นอน หวังว่าจะมีการเพิ่มการรองรับแลมด้าที่ดีขึ้นในภายหลัง
James

1
@avpx: มันไม่ใช่ฮีปพอร์ต เรารักษาฮีป 2 องค์ประกอบของ 2 รายการที่เล็กที่สุดที่เห็นเท่านั้นแทนที่จะรวมรายการทั้งหมดและทำให้องค์ประกอบทั้งหมดแตกต่างไปจากที่ฮีปพอร์ตทำได้
user2357112 รองรับ Monica

81

การใส่คำสั่งในรายการอาจจำลองหลายคำสั่ง:

เช่น:

lambda x: [f1(x), f2(x), f3(x), x+1]

9
เพื่อชี้แจงการเรียกใช้ฟังก์ชันไม่ถือว่าเป็นคำสั่งใน Python แต่เป็นนิพจน์ Noneดังนั้นรายการนี้เป็นเพียงรายการของการแสดงออกซึ่งทั้งหมดอาจจะเป็น
Yawar

ผมคิดว่างานนี้เพราะเมื่อวิเคราะห์แบบไดนามิกคอลเลกชันที่ผ่านมาแลมบ์ดาล่ามตรวจพบcallableลายเซ็นและการดำเนินการให้ ... คุณสามารถทดสอบกับ -> แลมบ์ดา x: [พิมพ์ (x) พิมพ์ (x + 1) พิมพ์ (x +2)]
ZEE

5
ยิ่งไปกว่านั้น: lambda x: [f1 (x), f2 (x)] [- 1] มันจะส่งคืนผลลัพธ์การคำนวณในรูปแบบนิพจน์สุดท้ายตามที่คาดไว้
Anton Ovsyannikov

22

นักท่องเวลาที่นี่ หากโดยทั่วไปคุณต้องการมีหลายคำสั่งภายในแลมบ์ดาคุณสามารถส่งแลมบ์ดาอื่น ๆ เป็นอาร์กิวเมนต์ไปยังแลมด้านั้นได้

(lambda x, f: list((y[1] for y in f(x))))(lst, lambda x: (sorted(y) for y in x))

คุณไม่สามารถมีหลายคำสั่งได้ แต่คุณสามารถจำลองได้โดยส่ง lambdas ไปยัง lambdas

แก้ไข:นักเดินทางข้ามเวลากลับมา! คุณยังสามารถใช้พฤติกรรมของนิพจน์บูลีนในทางที่ผิด (โดยคำนึงถึงกฎการลัดวงจรและความจริง) เพื่อดำเนินการต่อเนื่อง การใช้ตัวดำเนินการด้านท้ายช่วยให้คุณมีพลังมากขึ้น อีกครั้งคุณไม่สามารถมีหลายคำสั่งได้ แต่แน่นอนว่าคุณสามารถเรียกใช้ฟังก์ชันได้มากมาย ตัวอย่างนี้ใช้ขยะที่มีข้อมูลจำนวนมากตามอำเภอใจ แต่แสดงให้เห็นว่าคุณสามารถทำเรื่องตลก ๆ ได้ คำสั่งพิมพ์เป็นตัวอย่างของฟังก์ชันที่ส่งคืนNone(เช่นเดียวกับ.sort()วิธีการ) แต่ยังช่วยแสดงสิ่งที่lambdaกำลังทำอยู่

>>> (lambda x: print(x) or x+1)(10)
10
11
>>> f = (lambda x: x[::2] if print(x) or x.sort() else print(enumerate(x[::-1]) if print(x) else filter(lambda (i, y): print((i, y)) or (i % 3 and y % 2), enumerate(x[::-1]))))
>>> from random import shuffle
>>> l = list(range(100))
>>> shuffle(l)
>>> f(l)
[84, 58, 7, 99, 17, 14, 60, 35, 12, 56, 26, 48, 55, 40, 28, 52, 31, 39, 43, 96, 64, 63, 54, 37, 79, 25, 46, 72, 10, 59, 24, 68, 23, 13, 34, 41, 94, 29, 62, 2, 50, 32, 11, 97, 98, 3, 70, 93, 1, 36, 87, 47, 20, 73, 45, 0, 65, 57, 6, 76, 16, 85, 95, 61, 4, 77, 21, 81, 82, 30, 53, 51, 42, 67, 74, 8, 15, 83, 5, 9, 78, 66, 44, 27, 19, 91, 90, 18, 49, 86, 22, 75, 71, 88, 92, 33, 89, 69, 80, 38]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
(0, 99)
(1, 98)
(2, 97)
(3, 96)
(4, 95)
(5, 94)
(6, 93)
(7, 92)
(8, 91)
(9, 90)
(10, 89)
(11, 88)
(12, 87)
(13, 86)
(14, 85)
(15, 84)
(16, 83)
(17, 82)
(18, 81)
(19, 80)
(20, 79)
(21, 78)
(22, 77)
(23, 76)
(24, 75)
(25, 74)
(26, 73)
(27, 72)
(28, 71)
(29, 70)
(30, 69)
(31, 68)
(32, 67)
(33, 66)
(34, 65)
(35, 64)
(36, 63)
(37, 62)
(38, 61)
(39, 60)
(40, 59)
(41, 58)
(42, 57)
(43, 56)
(44, 55)
(45, 54)
(46, 53)
(47, 52)
(48, 51)
(49, 50)
(50, 49)
(51, 48)
(52, 47)
(53, 46)
(54, 45)
(55, 44)
(56, 43)
(57, 42)
(58, 41)
(59, 40)
(60, 39)
(61, 38)
(62, 37)
(63, 36)
(64, 35)
(65, 34)
(66, 33)
(67, 32)
(68, 31)
(69, 30)
(70, 29)
(71, 28)
(72, 27)
(73, 26)
(74, 25)
(75, 24)
(76, 23)
(77, 22)
(78, 21)
(79, 20)
(80, 19)
(81, 18)
(82, 17)
(83, 16)
(84, 15)
(85, 14)
(86, 13)
(87, 12)
(88, 11)
(89, 10)
(90, 9)
(91, 8)
(92, 7)
(93, 6)
(94, 5)
(95, 4)
(96, 3)
(97, 2)
(98, 1)
(99, 0)
[(2, 97), (4, 95), (8, 91), (10, 89), (14, 85), (16, 83), (20, 79), (22, 77), (26, 73), (28, 71), (32, 67), (34, 65), (38, 61), (40, 59), (44, 55), (46, 53), (50, 49), (52, 47), (56, 43), (58, 41), (62, 37), (64, 35), (68, 31), (70, 29), (74, 25), (76, 23), (80, 19), (82, 17), (86, 13), (88, 11), (92, 7), (94, 5), (98, 1)]

7

ใช้ฟังก์ชันเรียงลำดับดังนี้:

map(lambda x: sorted(x)[1],lst)

อาขอบคุณ (ชื่อที่สื่อความหมายสำหรับฟังก์ชั่น!) เป็นไปได้ไหม
ottodidakt

1
ไม่ "ฟังก์ชันที่สร้างด้วยรูปแบบแลมบ์ดาไม่สามารถมีคำสั่ง" docs.python.org/reference/expressions.html#lambda
alex vasi

1
-1: แลมบ์ดาและแผนที่แทนรายการความเข้าใจ? ไม่ pythonic มาก
nikow

@nikow [x [1] สำหรับ x ในการจัดเรียง (รายการ)] - วิธี pythonic?
RaGa__M

@Explorer_N: ไม่ต้องเรียงลำดับรายการ แต่ต้องเรียงองค์ประกอบของรายการ (ซึ่งเป็นรายการ) ในปัญหาปัจจุบัน ค่อนข้าง: [sorted(x)[1] for x in list_of_lists].
สูงสุด

6

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

map(lambda x: x.sort() or x[1],lst)

คุณต้องตรวจสอบให้แน่ใจว่าแต่ละคำสั่งไม่ส่งกลับอะไรเลยหรือถ้ามันรวมอยู่ใน (.. และ False) ผลลัพธ์คือสิ่งที่ส่งกลับมาจากการประเมินครั้งล่าสุด

ตัวอย่าง:

>>> f = (lambda : (print(1) and False) or (print(2) and False) or (print(3) and False))
>>> f()
1
2
3

5

ใช้ start () จากที่นี่: http://www.reddit.com/r/Python/comments/hms4z/ask_pyreddit_if_you_were_making_your_own/c1wycci

Python 3.2 (r32:88445, Mar 25 2011, 19:28:28) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]
>>> begin = lambda *args: args[-1]
>>> list(map(lambda x: begin(x.sort(), x[1]), lst))
[345, 465, 333]

4

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

ซึ่งคล้ายกับการใช้ "&&" เป็นตัวดำเนินการลัดวงจรในภาษาเชลล์เช่น bash

โปรดทราบ: คุณสามารถแก้ไขคำสั่งฟังก์ชันเพื่อส่งคืนค่าจริงได้โดยการตัดฟังก์ชัน

ตัวอย่าง:

def p2(*args):
    print(*args)
    return 1 # a true value

junky = lambda x, y: p2('hi') and p2('there') and p2(x) and p2(y)

junky("a", "b")

ในความคิดที่สองน่าจะดีกว่าที่จะใช้ 'หรือ' แทน 'และ' เนื่องจากฟังก์ชันจำนวนมากส่งคืน '0' หรือไม่มีในความสำเร็จ จากนั้นคุณสามารถกำจัดฟังก์ชัน wrapper ในตัวอย่างด้านบน:

junky = lambda x, y: print('hi') or print('there') or print(x) or print(y)

junky("a", "b")

'และ' ดำเนินการจะประเมินนิพจน์จนกว่าจะได้รับค่าที่ส่งกลับเป็นศูนย์แรก หลังจากนั้นก็ลัดวงจร 1 และ 1 และ 0 และ 1 ประเมิน: 1 และ 1 และ 0 และลดลง 1

'หรือ' ดำเนินการจะประเมินนิพจน์จนกว่าจะได้ค่าส่งคืนที่ไม่ใช่ศูนย์แรก หลังจากนั้นก็ลัดวงจร

0 หรือ 0 หรือ 1 หรือ 0 ประเมิน 0 หรือ 0 หรือ 1 และลดลง 0


3

หรือหากคุณต้องการหลีกเลี่ยงแลมด้าและมีเครื่องกำเนิดไฟฟ้าแทนรายการ:

(sorted (col) [1] สำหรับ col ใน lst)


2

ฉันขอนำเสนอแฮ็คที่น่าทึ่ง แต่น่ากลัวให้คุณ:

import types

def _obj():
  return lambda: None

def LET(bindings, body, env=None):
  '''Introduce local bindings.
  ex: LET(('a', 1,
           'b', 2),
          lambda o: [o.a, o.b])
  gives: [1, 2]

  Bindings down the chain can depend on
  the ones above them through a lambda.
  ex: LET(('a', 1,
           'b', lambda o: o.a + 1),
          lambda o: o.b)
  gives: 2
  '''
  if len(bindings) == 0:
    return body(env)

  env = env or _obj()
  k, v = bindings[:2]
  if isinstance(v, types.FunctionType):
    v = v(env)

  setattr(env, k, v)
  return LET(bindings[2:], body, env)

ตอนนี้คุณสามารถใช้LETแบบฟอร์มนี้ได้ดังนี้:

map(lambda x: LET(('_', x.sort()),
                  lambda _: x[1]),
    lst)

ซึ่งจะช่วยให้: [345, 465, 333]


โพสต์ครั้งแรกที่นี่: gist.github.com/divs1210/d218d4b747b08751b2a232260321cdeb
divs1210

1

คุณสามารถทำได้ในเวลา O (n) โดยใช้ min และ index แทนการใช้ sort หรือ heapq

ขั้นแรกให้สร้างรายการทุกอย่างใหม่ยกเว้นค่าต่ำสุดของรายการเดิม:

new_list = lst[:lst.index(min(lst))] + lst[lst.index(min(lst))+1:]

จากนั้นรับค่าต่ำสุดของรายการใหม่:

second_smallest = min(new_list)

ตอนนี้รวมกันเป็นแลมด้าเดียว:

map(lambda x: min(x[:x.index(min(x))] + x[x.index(min(x))+1:]), lst)

ใช่มันน่าเกลียดจริงๆ แต่ควรมีราคาถูกตามอัลกอริทึม เนื่องจากบางคนในหัวข้อนี้ต้องการดูความเข้าใจของรายการ:

[min(x[:x.index(min(x))] + x[x.index(min(x))+1:]) for x in lst]

1

นี่คือสิ่งที่bindฟังก์ชันในMonadใช้สำหรับ

ด้วยbindฟังก์ชันนี้คุณสามารถรวมแลมบ์ดาหลายตัวเป็นแลมด้าเดียวโดยแต่ละแลมด้าจะแสดงคำสั่ง


1

มีหลายวิธีที่คุณสามารถใช้หลายคำสั่งในแลมด้าได้ นี่คือวิธีแก้ปัญหาของฉัน:

lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]

x = lambda l: exec("l.sort(); return l[1]")

map(x, lst)

รหัสภายในexecไม่สามารถ
หยั่งรู้

0

ใช่. คุณสามารถกำหนดได้ด้วยวิธีนี้จากนั้นรวมหลายนิพจน์ของคุณด้วยสิ่งต่อไปนี้:

โครงการเริ่มต้น:

เริ่มต้น = แลมบ์ดา * x: x [-1]

การพยากรณ์โรค Lisp ทั่วไป:

การพยากรณ์ = แลมบ์ดา * x: x [-1]


0

มีวิธีแก้ปัญหาที่ดีกว่าโดยไม่ต้องใช้ฟังก์ชันแลมด้า แต่ถ้าเราต้องการใช้ฟังก์ชันแลมด้าจริงๆนี่คือวิธีแก้ปัญหาทั่วไปสำหรับจัดการกับคำสั่งหลาย ๆ คำสั่ง: map (lambda x: x [1] if (x.sort ()) else x [1], lst)

คุณไม่สนใจว่าคำสั่งนั้นจะส่งกลับมาอย่างไร


0

ใช่มันเป็นไปได้ ลองด้านล่างข้อมูลโค้ด

x = [('human', 1), ('i', 2), ('am', 1), ('.', 1), ('love', 1), ('python', 3), ('', 1),
  ('run', 1), ('is', 2), ('robust', 1), ('hello', 1), ('spark', 2), ('to', 1), ('analysis', 2), ('on', 1), ('big', 1), ('data', 1), ('with', 1), ('analysis', 1), ('great', 1)
]

rdd_filter = rdd1_word_cnt_sum.filter(lambda x: 'python' in x or 'human' in x or 'big' in x)
rdd_filter.collect()

-1

ฉันจะให้วิธีแก้ไขอื่นทำให้แลมด้าของคุณเรียกใช้ฟังก์ชัน

def multiple_statements(x, y):
    print('hi')
    print('there')
    print(x)
    print(y)
    return 1

junky = lambda x, y: multiple_statements(x, y)

junky('a', 'b');

7
ดียิ่งขึ้น: junky = multiple_statements.
Solomon Ucko
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.