Python 如何从功能上写出这个表达式?

Python 如何从功能上写出这个表达式?,python,lambda,functional-programming,Python,Lambda,Functional Programming,我想在功能上重写以下python代码: lst = [0.0] * 10 for pos in [2,5]: lst[pos] = 1.0 这是我的尝试,但不正确: lst = (lambda zeros: map( lambda pos: zeros[pos] = 1.0, [2,5]) )([0.0] * 10) 我得到的错误是lambda不能包含赋值 使用列表理解,解决方案是: lst = [ 1.0 if x in

我想在功能上重写以下python代码:

lst = [0.0] * 10
for pos in [2,5]:
    lst[pos] = 1.0
这是我的尝试,但不正确:

lst = (lambda zeros:
          map(
              lambda pos: zeros[pos] = 1.0, [2,5])
      )([0.0] * 10)
我得到的错误是
lambda不能包含赋值

使用列表理解,解决方案是:

lst = [ 1.0 if x in [2,5] else 0.0 for x in range(10) ]

我确实更喜欢你自己的答案中的列表理解,但如果我更注重功能性,我想我会使用
lambda
功能和
map

lazy = map(lambda element: 1 if element in [2,5] else 0, range(10))
请注意,
map
是Python 3中的惰性迭代器。如果您想要一个经过评估的
列表
,则必须将该行括在显式的
列表(…)
构造函数中:

lst = list(map(lambda element: 1 if element in [2,5] else 0, range(10)))

我确实更喜欢你自己的答案中的列表理解,但如果我更注重功能性,我想我会使用
lambda
功能和
map

lazy = map(lambda element: 1 if element in [2,5] else 0, range(10))
请注意,
map
是Python 3中的惰性迭代器。如果您想要一个经过评估的
列表
,则必须将该行括在显式的
列表(…)
构造函数中:

lst = list(map(lambda element: 1 if element in [2,5] else 0, range(10)))

列表理解法可能更好,但如果您正在寻找功能性的方法,那么以下方法如何:

lst = [0.0] * 10
lst = map(lambda (i, x): 1.0 if i in {2,5} else x, enumerate(lst))
#[0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0]
通过使用
enumerate(lst)
作为
map()
的iterable,我们可以得到索引和值。在这种情况下,如果
i
{2,5}
中,我们将得到0。否则,我们将保留值
x


如果您使用的是python3,则必须将对
map()
的调用包装为
list()
。然而,这种方法是因为它浪费了创建列表的时间。

列表理解方法可能更好,但是如果您正在寻找功能性的方法,那么这个方法如何:

lst = [0.0] * 10
lst = map(lambda (i, x): 1.0 if i in {2,5} else x, enumerate(lst))
#[0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0]
通过使用
enumerate(lst)
作为
map()
的iterable,我们可以得到索引和值。在这种情况下,如果
i
{2,5}
中,我们将得到0。否则,我们将保留值
x


如果您使用的是python3,则必须将对
map()
的调用包装为
list()
。但是,这种方法是因为它会浪费时间创建列表。

另一种方法是使用通用函数
展开

def unfold (f, acc):
  return f ( lambda x, next: [x] + unfold (f, next)
           , lambda x: [x] 
           , acc                          
           )

def main (ones):
  def value (i):
    return 1 if i in ones else 0   
  return unfold ( lambda next, done, i:
                    done (value (i)) if i >= 10 else next (value (i), i + 1)
                , 0
                )

print (main ( { 2, 5 }))
# [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
unfold
可以以有趣的方式使用

def alphabet ():
  return unfold ( lambda next, done, c:
                    done (c)            
                      if c == 'z' else
                        next (c, chr (ord (c) + 1))
                , 'a'
                )

print (alphabet ())
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
Python的lambda语法非常严格,其笨拙的三元语法使函数表达式编写起来非常困难。在下面的示例中,我们使用一些命令式语法预先定义了一个函数
gen
,以帮助可读性,然后将其传递给
unfold
——该程序还显示
state
可以是一个复杂的值

def fib (n):
  def gen (next, done, state):
    (n, a, b) = state
    if n == 0:
      return done (a)
    else:
      return next (a, (n - 1, b, a + b))
  return unfold (gen, (n, 0, 1))

print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
当然,所有这些痛苦都是有原因的——它是一个信号,表明我们做错了什么。一个经验丰富的python程序员决不会像我们上面所做的那样编写
main
alphabet
fib
。所以它不是pythonic(如他们所说),而是功能性的,希望能回答你的问题


下面,我们大大简化了
展开
——我们要求用户返回一个对其选择进行编码的元组:
(值,无)
表示
是序列中的最后一个值,
(值,下一个状态)
将生成下一个值并继续下一个状态

这里的折衷是
展开
稍微不那么复杂,但它需要用户知道编写程序所需的特殊元组信号。在此之前,
next
done
让用户不再担心这个问题。无论哪种方式都可以,我分享这一点只是为了给出另一种选择

def unfold (f, acc):
  (x, nextAcc) = f (acc)
  if nextAcc is None:
    return [x]
  else:
    return [x] + unfold (f, nextAcc)

def fib (n):
  def gen (state):
    (n, a, b) = state
    if n == 0:
      return (a, None)
    else:
      return (a, (n - 1, b, a + b))
  return unfold (gen, (n, 0, 1))

print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]

另一种方法是使用通用函数
unfold

def unfold (f, acc):
  return f ( lambda x, next: [x] + unfold (f, next)
           , lambda x: [x] 
           , acc                          
           )

def main (ones):
  def value (i):
    return 1 if i in ones else 0   
  return unfold ( lambda next, done, i:
                    done (value (i)) if i >= 10 else next (value (i), i + 1)
                , 0
                )

print (main ( { 2, 5 }))
# [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
unfold
可以以有趣的方式使用

def alphabet ():
  return unfold ( lambda next, done, c:
                    done (c)            
                      if c == 'z' else
                        next (c, chr (ord (c) + 1))
                , 'a'
                )

print (alphabet ())
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
Python的lambda语法非常严格,其笨拙的三元语法使函数表达式编写起来非常困难。在下面的示例中,我们使用一些命令式语法预先定义了一个函数
gen
,以帮助可读性,然后将其传递给
unfold
——该程序还显示
state
可以是一个复杂的值

def fib (n):
  def gen (next, done, state):
    (n, a, b) = state
    if n == 0:
      return done (a)
    else:
      return next (a, (n - 1, b, a + b))
  return unfold (gen, (n, 0, 1))

print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
当然,所有这些痛苦都是有原因的——它是一个信号,表明我们做错了什么。一个经验丰富的python程序员决不会像我们上面所做的那样编写
main
alphabet
fib
。所以它不是pythonic(如他们所说),而是功能性的,希望能回答你的问题


下面,我们大大简化了
展开
——我们要求用户返回一个对其选择进行编码的元组:
(值,无)
表示
是序列中的最后一个值,
(值,下一个状态)
将生成下一个值并继续下一个状态

这里的折衷是
展开
稍微不那么复杂,但它需要用户知道编写程序所需的特殊元组信号。在此之前,
next
done
让用户不再担心这个问题。无论哪种方式都可以,我分享这一点只是为了给出另一种选择

def unfold (f, acc):
  (x, nextAcc) = f (acc)
  if nextAcc is None:
    return [x]
  else:
    return [x] + unfold (f, nextAcc)

def fib (n):
  def gen (state):
    (n, a, b) = state
    if n == 0:
      return (a, None)
    else:
      return (a, (n - 1, b, a + b))
  return unfold (gen, (n, 0, 1))

print (fib (20))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]

这怎么不正确呢?它是否抛出异常或给出错误的答案?无论哪种方式,都要在你的问题中包含这一点。
lst=[0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0]
;)您的列表理解功能更强,因为它不会破坏输入。函数式编程的一个非常重要的组成部分是不变性和引用透明性。这保证了表达式的可互换性。即使在Haskell中,列表理解也非常方便和实用。它怎么会不正确呢?它是否抛出异常或给出错误的答案?无论哪种方式,都要在你的问题中包含这一点。
lst=[0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0]
;)您的列表理解功能更强,因为它不会破坏输入。函数式编程的一个非常重要的组成部分是不变性和引用性