python sum 函数中可以使用条件语句吗
高洛峰
高洛峰 2017-04-17 17:52:13
0
2
1158

我在学习协同过滤,遇到这样一段代码

def sim_distance(prefs,person1,person2):
  # Get the list of shared_items
  si={}
  for item in prefs[person1]: 
    if item in prefs[person2]: si[item]=1

  # if they have no ratings in common, return 0
  if len(si)==0: return 0

  # Add up the squares of all the differences
  sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                      for item in prefs[person1] if item in prefs[person2]])

  return 1/(1+sum_of_squares)

比较困惑的是下面这段代码,为什么sum里面可以写for 循环呢,这个是什么意思,为什么我写了个类似的函数就会报错

sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                          for item in prefs[person1] if item in prefs[person2]])
高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

Antworte allen(2)
刘奇

sum接受的第一个参数是个iterable。楼主想知道这个for循环的含义,要去查看一下生成器以及生成器相关的语法糖,这里给楼主一个简单的例子[i for i in range(5)] # 结果为[0,1,2,3,4]

洪涛

這邊的 for 或是 if 都跟 sum 本身沒有什麼關係,如同 @大鹌鹑 所說,sum 接受一個可迭代的對象作為參數,至於這個例子中的可迭代對象就一個 使用 list comprehension 產生的 list


那就稍為介紹一下 list comprehension(串列產生式) 好了。

這是一個帶有 functional programming 味道的語法,直覺而優雅。

顧名思義,他是為了產生 串列 而被使用。

因此有一個重要的原則就是:

當今天代碼的目的是為了要生成一個 list ,那我們應當考慮使用他,否則完全不應該使用


我們來看一下用法,非常簡單的,為了生成串列,所以我們字面上使用兩個成對的中括號 [] ( list 的字面產生語法),夾住一個 for...in... 迭代式,利用 for 走訪到的元素會被依序用來製造 list 中的各個元素。

讓我們看例子,假設今天我們有一個整數的串列 lst,我們想要製造另外一個串列 lst2,其中的每個元素都是 lst 中元素的平方:

lst = [1, 2, 3, 4]
lst2 = []

for i in lst:
    lst2.append(i**2)

我們使用了一個標準的 for...in... 迴圈來作到這件事,但同樣的事情,我們能夠用 list comprehension 作得更簡潔更優雅:

lst = [1, 2, 3, 4]
lst2 = [i**2 for i in lst]

在這個例子中,for i in lst 會依序取出 lst 中的元素進行平方運算後成為 lst2 的新元素。 這讓人聯想到 map function,我們同樣可以使用 映射 來作到類似的效果:

lst = [1, 2, 3, 4]
lst2 = map(lambda x:x**2, lst)  # Python2
lst2 = list(map(lambda x:x**2, lst))  # Python3

map 會依序走訪他第二個參數(一個可迭代對象)中的元素,並且將元素作為引數,調用他的第一個參數(一個單參數函數),也就是會依序取出 1, 2, 3 ,4 然後將之當成參數 x 調用匿名函數 lambda x:x**2

但我們可以發現 list comprehension 更加直覺,我們可以說 list comprehension 中的 for述句就是在 map 的良好替代品。


說到 map 就會想到 filter,他會對可迭代物件進行過濾的動作。

比如說我想讓 lst2 裡面只出現奇數:

lst = [1, 2, 3, 4]
lst2 = filter(lambda x:x%2!=0, map(lambda x:x**2, lst))  # Python2
lst2 = list(filter(lambda x:x%2!=0, map(lambda x:x**2, lst)))  # Python3

filter 一樣會去走訪他的第二個參數(一個可迭代對象),並依序取出當成引數,調用他的第一個參數(一個單參數函數),若運算的結果為真( True ),則保留此回傳值作為新的元素,反之( False )會被過濾掉。

而現在 filter 也有了替代品,就是 list comprehension,我們可以這樣寫:

lst = [1, 2, 3, 4]
lst2 = [i**2 for i in lst if i%2!=0]

同樣也是簡單許多! 我們可以說 list comprehension 中的 if 述句就是 filter 的良好替代品。


看到這裡,相信你已經明白:

sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                          for item in prefs[person1] if item in prefs[person2]])

這段代碼,是先執行了一個含有 for...in... 述句和 if 述句的 list comprehension 來產生 list 後,才以該 list 作為引數調用 sum 函數。


結論:

  1. for...in...ifsum 沒有直接關係。

  2. for...in...if 是 list comprehension 的關鍵語法。

  3. list comprehension 可以幫助我們使用可迭代對象產生 list。

  4. list comprehension 是 mapfilter 的良好替代品。

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage