jq에서는 다음과 같은 관계 연산자와 동등 연산자로 숫자를 비교할 수 있어요.
| 비교 | 연산자 |
|---|---|
| ~보다 큼 | a > b |
| ~보다 크거나 같음 | a >= b |
| ~보다 작음 | a < b |
| ~보다 작거나 같음 | a <= b |
| 같음 | a == b |
| 같지 않음 | a != b |
비교 결과는 항상 불리언 값이에요. 즉 true나 false 중 하나예요.
1 < 3, # => true
2 != 2, # => false
1 == 1.0 # => true
# All numbers are floating-points, so this is different syntax
# for the exact same value.
위의 비교 연산자로 문자열도 비교할 수 있어요. 이 경우에는 딕셔너리(사전식) 순서가 적용돼요. 정렬 순서는 _유니코드 코드 포인트 값_을 기준으로 해요.
"Apple" > "Pear", # => false
"a" < "above", # => true
"a" == "A" # => false
숫자 값을 담고 있는 것처럼 보이지만 문자열 타입인 두 변수를 비교할 때는 주의해야 해요. 딕셔너리 순서 때문에 그 결과는 숫자 타입 값을 비교한 결과와 같지 않아요.
10 < 2, # => false
"10" < "2" # => true (because "1" comes before "2")
jq의 == 연산자는 JavaScript의 ===와 비슷해요. 겉보기에는 같아 보이지만 타입이 다르면 같지 않다고 판단한다는 점에서요.
"3" == 3 # => false
# the value on the left has type string,
# the value on the right has type number.
두 배열은 대응하는 모든 원소가 같으면 서로 같아요.
[1, 2, 3] == [1, 2, 3] # => true
[1, 2, 3] == [1, 3, 2] # => false, different order
[1, 2, 3] == [1, 2, "3"] # => false, different types
두 객체는 키-값 쌍이 같으면 서로 같아요.
{name: "Joe", age: 42} == {age: 42, name: "Joe"} # => true
{name: "Joe", age: 42} == {age: 42, name: "Jane"} # => false
{name: "Joe", age: 42} == {age: "42", name: "Joe"} # => false
{name: "Joe", age: 42} == {age: 42, name: "Joe", height: 175} # => false
# comparisons will drill down as deeply as required
{a: {b: {c: [1, 2]}}} == {a: {b: {c: [1, 2]}}} # => true
{a: {b: {c: [1, 2]}}} == {a: {b: {c: [1, 2, 3]}}} # => false
jq의 조건 표현식은 if A then B else C end예요.
if-then-else는 다른 모든 jq 내장 기능과 마찬가지로 필터예요. 입력을 받아 출력을 만들어요.
표현식 A가 "truthy" 값을 만들어 내면 if 필터는 B를 평가해요.
그렇지 않으면 C를 평가해요.
if 필터의 입력은 B나 C로 전달돼요.
42 | if . < 50 then "small" else "big" end # => "small"
5 | if . % 2 == 0 then . / 2 else . * 4 end # => 20
else 절은 선택 사항이에요. 다음 두 문은 서로 동등해요.
if A then B else . end
if A then B end
elif로 조건을 더 추가할 수 있어요.
42 | if . < 33 then "small"
elif . < 66 then "medium"
else "big"
end
# => "medium"
elif 절은 필요한 만큼 사용하면 돼요.
jq에서 "거짓"인 값은 false와 null뿐이에요.
나머지는 모두 "참"이에요. 숫자 0과 빈 문자열, 빈 배열, 빈 객체까지도요.
불리언 연산자 and와 or를 사용하면 복잡한 질의를 만들 수 있어요.
42 | if . < 33 or . > 66 then "big or small"
else "medium"
end
부정하려면 not을 사용해요. 이건 연산자가 아니라 필터예요.
42 | if (. < 33 or . > 66 | not) then "medium"
else "big or small"
end
대체 연산자를 사용하면 표현식이 false나 null일 때 사용할 "기본" 값을 지정할 수 있어요.
A // B
# This is identical to
if A then A else B end
예를 들어 볼까요.
[3, 5, 18] | add / 2 # => 13
[] | add / 2 # => error: null (null) and number (2) cannot be divided
[] | add // 0 / 2 # => 0
이 연습 문제에서는 차량 구매를 준비하는 데 도움이 되는 코드를 작성해요.
해야 할 과제는 세 가지예요. 운전면허가 필요한지 판단하기, 두 차량 중에서 고르기, 그리고 중고 차량의 적정 가격을 추정하기예요.
어떤 종류의 차량은 운전하려면 운전면허가 필요해요.
"car"와 "truck" 종류만 면허가 필요하고, 나머지는 모두 면허 없이 운전할 수 있다고 가정해요.
차량의 종류를 받아서, 그 종류의 차량에 면허가 필요한지를 나타내는 불리언을 반환하는 needs_license 함수를 구현해요.
"car" | needs_license
# => true
"bike" | needs_license
# => false
구매 가능한 차량들을 살펴봤어요.
후보를 두 개로 좁혔지만, 최종 결정을 내리려면 도움이 필요해요.
차량 두 대가 담긴 배열을 입력으로 받아서, 사전 순으로 앞서는 쪽을 결정으로 반환하는 choose_vehicle 함수를 구현해요.
["Wuling Hongguang", "Toyota Corolla"] | choose_vehicle
# => "Toyota Corolla is clearly the better choice."
["Volkswagen Beetle", "Volkswagen Golf"] | choose_vehicle
# => "Volkswagen Beetle is clearly the better choice."
이제 결정을 내렸으니, 대리점에서 적정한 가격에 사고 싶어요. 중고 차량을 사려고 하니, 가격은 차량의 연식에 따라 달라져요. 대략적으로 추정해 보면, 차량이 3년 미만이면 새 차였을 때의 원래 가격에서 80%라고 가정해요. 10년이 넘으면 50%예요. 차량이 3년 이상이면서 10년 이하이면 원래 가격의 70%예요.
if, elif, else를 사용해 이 로직을 적용하는 resell_price 함수를 구현해요.
원래 가격과 차량의 연식이 담긴 객체를 받아서 대리점에서의 추정 가격을 반환해요.
{"original_price": 1000, "age": 1} | resell_price
# => 800
{"original_price": 1000, "age": 5} | resell_price
# => 700
{"original_price": 1000, "age": 15} | resell_price
# => 500