只能針對一個 TRUE 或是 FALSE 做執行:
if (condition) {true_action}if (condition) {true_action} else {false_action}if (condition1) {true_action1} else if (condition2) {true_action2} else {false_action}?`if`
grade <- function(x) {
if (x > 90) {
"A"
} else if (x > 80) {
"B"
} else if (x > 50) {
"C"
} else {
"F"
}
}
x1 <- if (TRUE) 1 else 2
x2 <- if (FALSE) 1 else 2
c(x1, x2)
## [1] 1 2
# if ("x") 1
# #> Error in if ("x") 1 : 引數無法解譯為邏輯值
# if (logical()) 1
# #> Error in if (logical()) 1 : 引數長度為零
# if (NA) 1
# #> Error in if (NA) 1 : 需要 TRUE/FALSE 值的地方有缺值
if (c(TRUE, FALSE)) 1
## Warning in if (c(TRUE, FALSE)) 1: 條件的長度 > 1,因此只能用其第一元素
## [1] 1
if (c(TRUE, TRUE)) 1
## Warning in if (c(TRUE, TRUE)) 1: 條件的長度 > 1,因此只能用其第一元素
## [1] 1
# x <- 10
# if (x < 3) {
# x <- 0
# }
# else {
# x
# }
ifelse()?ifelse
x <- c(6:-4)
sqrt(x) #- gives warning
## Warning in sqrt(x): 產生了 NaNs
## [1] 2.449490 2.236068 2.000000 1.732051 1.414214 1.000000 0.000000 NaN
## [9] NaN NaN NaN
sqrt(ifelse(x >= 0, x, NA)) # no warning
## [1] 2.449490 2.236068 2.000000 1.732051 1.414214 1.000000 0.000000 NA
## [9] NA NA NA
## Note: the following also gives the warning !
ifelse(x >= 0, sqrt(x), NA)
## Warning in sqrt(x): 產生了 NaNs
## [1] 2.449490 2.236068 2.000000 1.732051 1.414214 1.000000 0.000000 NA
## [9] NA NA NA
set.seed(100)
d <- sample(x = 20:60, size = 100, replace = TRUE)
d
## [1] 29 57 44 33 42 41 25 23 25 53 26 26 37 31 54 27 37 44 21 23 23 51 40 46 58
## [26] 35 30 21 25 48 49 49 48 42 50 52 50 48 47 50 60 60 60 43 26 20 28 57 39 33
## [51] 33 43 22 55 46 24 23 31 35 41 37 22 24 40 47 44 34 31 56 45 58 43 31 28 30
## [76] 54 45 60 35 56 49 46 37 27 46 27 21 38 50 42 31 45 24 33 59 36 31 49 59 50
ifelse(d >= 40, ifelse(d >= 60, "C", "B"), "A")
## [1] "A" "B" "B" "A" "B" "B" "A" "A" "A" "B" "A" "A" "A" "A" "B" "A" "A" "B"
## [19] "A" "A" "A" "B" "B" "B" "B" "A" "A" "A" "A" "B" "B" "B" "B" "B" "B" "B"
## [37] "B" "B" "B" "B" "C" "C" "C" "B" "A" "A" "A" "B" "A" "A" "A" "B" "A" "B"
## [55] "B" "A" "A" "A" "A" "B" "A" "A" "A" "B" "B" "B" "A" "A" "B" "B" "B" "B"
## [73] "A" "A" "A" "B" "B" "C" "A" "B" "B" "B" "A" "A" "B" "A" "A" "A" "B" "B"
## [91] "A" "B" "A" "A" "B" "A" "A" "B" "B" "B"
switch()switch與if else關係密切。在大多數的情況之下,可用switch改寫if else控制語句。x_option <- function(x) {
if (x == "a") {
"option 1"
} else if (x == "b") {
"option 2"
} else if (x == "c") {
"option 3"
} else {
stop("Invalid `x` value")
}
}
可改寫為:
?switch
x_option <- function(x) {
switch(x,
a = "option 1",
b = "option 2",
c = "option 3",
stop("Invalid `x` value")
)
}
x_option("a")
## [1] "option 1"
x_option("b")
## [1] "option 2"
# x_option("v")
# Error in x_option("v") : Invalid `x` value
centre <- function(x, type) {
switch(type,
mean = mean(x),
median = median(x),
trimmed = mean(x, trim = .1))
}
set.seed(seed = 100)
x <- rcauchy(10)
centre(x, "mean")
## [1] 2.178666
centre(x, "median")
## [1] 0.8209592
centre(x, "trimmed")
## [1] 1.122283
centre(x, 1)
## [1] 2.178666
centre(x, 2)
## [1] 0.8209592
centre(x, 3)
## [1] 1.122283
centre(x, "trimed")
centre(x, 4)
ans <- centre(x, 4)
ans
## NULL
(switch("c", a = 1, b = 2))
## NULL
switch()還有一個方便的功能-當多個參數共用一個回傳值時:legs <- function(x) {
switch(x,
cow = ,
horse = ,
dog = 4,
human = ,
chicken = 2,
plant = 0,
stop("Unknown input")
)
}
legs(x = "cow")
## [1] 4
legs(x = "human")
## [1] 2
for (item in vector) { perform_action }for (i in 1:3) {
print(i ^ 2)
}
## [1] 1
## [1] 4
## [1] 9
# N.B.: for assigns the item to the current environment, overwriting any existing variable with the same name:
i <- 100
for (i in 1:3) {}
i
## [1] 3
有兩個方法可提前終止for loop:
next:
離開當下的loop,回到loop的頂部,繼續下一次的
break: 離開整個loop
for (i in 1:10) {
if (i < 3)
next
print(i)
if (i >= 5)
break
}
## [1] 3
## [1] 4
## [1] 5
means <- c(1, 50, 20)
out <- vector("list", length(means))
for (i in 1:length(means)) {
out[[i]] <- rnorm(10, means[[i]])
}
length(x)為0(為空向量)時,需小心使用1:length(x):means <- c()
out <- vector("list", length(means))
# for (i in 1:length(means)) {
# out[[i]] <- rnorm(10, means[[i]])
# }
# Error in rnorm(10, means[[i]]) : invalid arguments
1:length(means)
## [1] 1 0
seq_along(means)
## integer(0)
out <- vector("list", length(means))
for (i in seq_along(means)) {
out[[i]] <- rnorm(10, means[[i]])
}
out
## list()
當你事先無法確定需要運算的次數,進而無法預先配置物件大小時,有以下兩種工具可使用:
while(): while( condition) action: performs action while condition is TRUE.repeat():repeat action forever (i.e. until it encounters break).簡單範例如下:
if 1:
print('true!!!')
## true!!!
if not 1:
print('true!!!')
else:
print('false!!!')
## false!!!
x = 'killer rabbit'
if x == 'roger':
print("shave and a haircut")
elif x == 'bugs':
print("what's up doc?")
else:
print('Run away! Run away!')
## Run away! Run away!
switch述句可以使用if-else述句來替代dict做替代方案,會更具彈性-類似switch的功能choice = 'eggs'
print({'spam': 1.25,
'ham': 1.99,
'eggs': 0.99,
'bacon': 1.10}[choice])
## 0.99
也可利用dict的方法-get():
branch = {'spam': 1.25, 'ham': 1.99, 'eggs': 0.99}
print(branch.get('spam', 'Bad choice'))
## 1.25
print(branch.get('bacon', 'Bad choice'))
## Bad choice
當然,也可以用if-else來改寫:
choice = 'bacon'
if choice in branch:
print(branch[choice])
else:
print('Bad choice')
## Bad choice
更建議用try的語法來實現:
try:
print(branch[choice])
except KeyError:
print('Bad choice')
## Bad choice
def default(x):
pass
branch = {'spam': lambda x: x ** 2,
'ham': lambda x: 10 * x,
'eggs': lambda x: x / 2
}
choice = 'eggs'
branch.get(choice, default)(10)
## 5.0
branch.get('NCCU', default)(10)
可改寫成:
A = 't' if 'spam' else 'f'
A
## 't'
A = 't' if '' else 'f'
A
## 'f'
['t', 'f'][bool('spam')]
## 'f'
['t', 'f'][bool('')]
## 't'
x = 'NCCU'
while x:
print(x, end = '\n')
x = x[1:]
## NCCU
## CCU
## CU
## U
a = 0; b = 10
while a < b: # One way to code counter loops
print(a, end=' ')
a += 1
## 0 1 2 3 4 5 6 7 8 9
# data = get_data()
# while data != "":
# if "Good" in data:
# print("找到單字Good")
# break
# data = get_data()
# else:
# print("找不到單字Good")
範例:找出第一次出現數字1的位置:
x = [0, 0, 0, 1, 1, 0]
for i in range(0, len(x)):
if x[i] == 1: break
i
## 3
# Python code:
x = 10
while x:
x = x - 1
if x % 2 != 0:
continue
print(x, end = '\n')
## 8
## 6
## 4
## 2
## 0
# R code:
x <- 10
while(x != 0) {
x <- x - 1
if (x %% 2 != 0) {
next
}
cat(x, sep = "\n")
}
## 8
## 6
## 4
## 2
## 0
# Python code:
def func1():
pass # Add real code here later
type(func1)
## <class 'function'>
# R code:
func1 <- function() {
}
class(func1)
## [1] "function"
# Python code:
x = 10
if x < 5:
pass
else:
x = 5
x
## 5
# R code:
x <- 10
if (x < 5) {
} else {
x <- 5
}
x
## [1] 5
y = 4
x = y // 2
while x > 1:
if y % x == 0:
print(y, 'has factor', x)
break
x -= 1
else:
print(y, 'is prime')
## 4 has factor 2
for x in ["spam", "eggs", "ham"]:
print(x, end = ' ')
## spam eggs ham
sum = 0
for x in [1, 2, 3, 4]:
sum = sum + x
sum
## 10
S = "lumberjack"
T = ("and", "I'm", "okay")
for x in S:
print(x, end=' ')
## l u m b e r j a c k
for x in T: print(x, end = ' ')
## and I'm okay
T = [(1, 2), (3, 4), (5, 6)]
for a, b in T: # Tuple assignment at work
print(a, b)
## 1 2
## 3 4
## 5 6
D = {'a':1, 'b':2, 'c':3}
for key in D:
print(key, '=>', D[key]) # Use dict keys iterator and index
## a => 1
## b => 2
## c => 3
D = {'a':1, 'b':2, 'c':3}
list(D.items()) # 用iterms()傳回所有的鍵與值,相對應的鍵值會存放在tuple內,並轉換為list
## [('a', 1), ('b', 2), ('c', 3)]
for key, value in D.items():
print(key, '=>', value)
## a => 1
## b => 2
## c => 3
T = [(1, 2), (3, 4), (5, 6)]
for both in T:
a, b = both
print(a, b)
## 1 2
## 3 4
## 5 6
for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]: print(a, b, c)
## 1 2 3
## 4 5 6
for (a, *b, c) in [(1, 2, 3, 4), (5, 6, 7, 8)]: print(a, b, c)
## 1 [2, 3] 4
## 5 [6, 7] 8
items = ["aaa", 111, (4, 5), 2.01] # A set of objects
tests = [(4, 5), 3.14] # Keys to search for
for key in tests: # For all keys
for item in items: # For all items
if item == key: # Check for match
print(key, "was found")
break
else:
print(key, "not found!")
## (4, 5) was found
## 3.14 not found!
亦可以改寫更簡單的程式碼:
for key in tests:
if key in items:
print(key, 'was found')
else:
print(key, 'not found!')
## (4, 5) was found
## 3.14 not found!
seq1 = 'spam'
seq2 = 'scam'
res = []
for x in seq1:
if x in seq2:
res.append(x)
res
## ['s', 'a', 'm']
[x for x in seq1 if x in seq2]
## ['s', 'a', 'm']
def echo(message):
print(message)
schedule = [(echo, 'NCCU'), (echo, 'Money and Banking')]
for (f, args) in schedule:
f(args)
## NCCU
## Money and Banking
range()S = 'spam'
for i in range(len(S)):
S = S[1:] + S[:1]
print(S, end=' ')
## pams amsp mspa spam
L = [1, 2, 3]
for i in range(len(L)):
X = L[i:] + L[:i]
print(X, end=' ')
## [1, 2, 3] [2, 3, 1] [3, 1, 2]
S = 'abcdefghijk'
list(range(0, len(S), 2))
## [0, 2, 4, 6, 8, 10]
for i in range(0, len(S), 2):
print(S[i], end=' ')
## a c e g i k
zip()L1 = [1,2,3,4]
L2 = [5,6,7,8]
zip(L1, L2)
## <zip object at 0x7fe6fb72fdc0>
list(zip(L1, L2))
## [(1, 5), (2, 6), (3, 7), (4, 8)]
for (x, y) in zip(L1, L2):
print(x, y, '--', x+y)
## 1 5 -- 6
## 2 6 -- 8
## 3 7 -- 10
## 4 8 -- 12
T1, T2, T3 = (1,2,3), (4,5,6), (7,8,9)
T3
## (7, 8, 9)
list(zip(T1, T2, T3))
## [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
S1 = 'abc'
S2 = 'xyz123'
list(zip(S1, S2)) # # Truncates at len(shortest)
## [('a', 'x'), ('b', 'y'), ('c', 'z')]
Z = zip((1, 2, 3), (10, 20, 30)) # zip is the same: a one-pass iterator
Z
## <zip object at 0x7fe6fb730740>
list(Z)
## [(1, 10), (2, 20), (3, 30)]
for pair in Z: print(pair) # Exhausted after one pass
Z = zip((1, 2, 3), (10, 20, 30)) # Manual iteration (iter() not needed)
next(Z)
## (1, 10)
next(Z)
## (2, 20)
enumerate()S = 'spam'
list(enumerate(S))
## [(0, 's'), (1, 'p'), (2, 'a'), (3, 'm')]
for (offset, item) in enumerate(S):
print(item, 'appears at offset', offset)
## s appears at offset 0
## p appears at offset 1
## a appears at offset 2
## m appears at offset 3
S = 'spam'
E = enumerate(S) # generator object
E
## <enumerate object at 0x7fe6fb737d40>
next(E)
## (0, 's')
next(E)
## (1, 'p')
next(E)
## (2, 'a')
next(E)
# next(E)
# StopIteration:
#
# Detailed traceback:
# File "<string>", line 1, in <module>
## (3, 'm')
map()map與range類似,內建函數map、zip、在Python
3.X中可得iterable
object以節省內存的空間,不需在內存中一次性產生一個結果listmap與range不同,回傳本身就是一個iteratormap的效能比for loop高M = map(abs, [-1, 0, 1]) # map returns an iterable, not a list
M
## <map object at 0x7fe6fb739610>
next(M) # Use iterator manually: exhausts results
## 1
next(M)
## 0
next(M)
## 1
for x in M: print(x) # no results
M = map(abs, [-1, 0, 1])
for x in M: print(x)
## 1
## 0
## 1
list(map(abs, (-1, 0, 1))) # Can force a real list if needed
## [1, 0, 1]
L = [1, 2, 3]
I = iter(L) # Obtain an iterator object from an iterable
I.__next__()
## 1
I.__next__()
## 2
I.__next__()
# I.__next__()
# StopIteration:
#
# Detailed traceback:
# File "<string>", line 1, in <module>
## 3
L = [1, 2, 3]
iter(L) is L
# L.__next__()
# AttributeError: 'list' object has no attribute '__next__'
## False
I = iter(L)
I.__next__()
## 1
next(I) # Same as I.__next__()
## 2
L = [1, 2, 3]
for X in L: # Automatic iteration
print(X ** 2, end = ' ') # Obtains iter, calls __next__, catches exceptions
## 1 4 9
L = [1, 2, 3]
I = iter(L) # Manual iteration: what for loops usually do
while True:
try: # try statement catches exceptions
X = next(I)
except StopIteration:
break
print(X ** 2, end=' ')
## 1 4 9
D = {'a':1, 'b':2, 'c':3}
for key in D.keys():
print(key, D[key])
## a 1
## b 2
## c 3
D = {'a':1, 'b':2, 'c':3}
I = iter(D)
I.__next__()
## 'a'
next(I)
## 'b'
next(I)
# next(I)
# StopIteration:
#
# Detailed traceback:
# File "<string>", line 1, in <module>
## 'c'
L = [1, 2, 3, 4, 5]
for i in range(len(L)):
L[i] += 10
L
## [11, 12, 13, 14, 15]
L = [1, 2, 3, 4, 5]
L = [x + 10 for x in L]
L
## [11, 12, 13, 14, 15]
L = [1, 2, 3, 4, 5]
L = [x ** 2 for x in L if x % 2 == 0]
L
## [4, 16]
res = []
for x in ['2020', '2021']:
for y in ['/一月', '/二月', '/三月']:
res.append(x + y)
res
## ['2020/一月', '2020/二月', '2020/三月', '2021/一月', '2021/二月', '2021/三月']
res = [x + y for x in ['2020', '2021'] for y in ['/一月', '/二月', '/三月']]
res
## ['2020/一月', '2020/二月', '2020/三月', '2021/一月', '2021/二月', '2021/三月']
new_dict = {expr1: expr2 for variable in list if condition}x = [1, 2, 3, 4]
x_squared_dict = {item: item * item for item in x}
x_squared_dict
## {1: 1, 2: 4, 3: 9, 4: 16}
range 支援len與索引取值(indexing):R = range(5)
len(R)
## 5
R[0]
## 0
range 支援 Multiple Iterators:R = range(3) # range allows multiple iterators
# next(R)
# TypeError: 'range' object is not an iterator
I1 = iter(R)
next(I1)
## 0
next(I1)
## 1
I2 = iter(R)
next(I2)
## 0
next(I2)
## 1
zip , map
則『不』支援Multiple Iterators,為 Single
Iterator:Z = zip((1, 2, 3), (10, 20, 30))
I1 = iter(Z)
I2 = iter(Z)
next(I1)
## (1, 10)
next(I1)
## (2, 20)
next(I2)
## (3, 30)
M = map(abs, (-1, 0, 1))
I1 = iter(M)
I2 = iter(M)
print(next(I1), next(I1), next(I1))
# next(I2)
# StopIteration:
## 1 0 1
R = range(3)
I1, I2 = iter(R), iter(R)
[next(I1), next(I1), next(I1)]
## [0, 1, 2]
next(I2)
## 0
D = {'a': 1, 'b': 2, 'c': 3}
D
## {'a': 1, 'b': 2, 'c': 3}
K = D.keys()
K
# next(K) # K are not iterators themselves
# TypeError: 'dict_keys' object is not an iterator
## dict_keys(['a', 'b', 'c'])
I = iter(K)
next(I)
## 'a'
next(I)
## 'b'
for k in D.keys(): print(k, end=' ')
## a b c