루비에서 0 값을 매핑하고 제거하는 방법
나는 있습니다map값을 변경하거나 0으로 설정합니다.그런 다음 목록에서 0 항목을 제거합니다.그 목록은 보관할 필요가 없습니다.
제가 현재 가지고 있는 것은 다음과 같습니다.
# A simple example function, which returns a value or nil
def transform(n)
rand > 0.5 ? n * 10 : nil }
end
items.map! { |x| transform(x) } # [1, 2, 3, 4, 5] => [10, nil, 30, 40, nil]
items.reject! { |x| x.nil? } # [10, nil, 30, 40, nil] => [10, 30, 40]
루프를 수행하여 다음과 같은 다른 어레이에서 조건부로 수집할 수 있습니다.
new_items = []
items.each do |x|
x = transform(x)
new_items.append(x) unless x.nil?
end
items = new_items
하지만 그것은 그렇게 관용적으로 보이지 않습니다.목록 위에 함수를 매핑하여 이동하면서 네일을 제거/제외하는 좋은 방법이 있습니까?
다음을 사용할 수 있습니다.
[1, nil, 3, nil, nil].compact
=> [1, 3]
저는 사람들에게 만약 당신이 닐이 포함된 배열을 출력물로 받는다면 상기시켜주고 싶습니다.map블록, 그리고 그 블록은 조건부로 값을 반환하려고 시도합니다. 그러면 코드 냄새가 나고 논리를 다시 생각해야 합니다.
예를 들어, 다음과 같은 작업을 수행하는 경우:
[1,2,3].map{ |i|
if i % 2 == 0
i
end
}
# => [nil, 2, nil]
그럼 하지 마세요. 앞에, 에신대.map,reject 않는 당이원하않것는혹들은지신▁you혹은▁the것들▁stuff▁don.select원하는 것:
[1,2,3].select{ |i| i % 2 == 0 }.map{ |i|
i
}
# => [2]
는 사을고려다니합을 사용하는 것을 합니다.compact우리가 제대로 처리하지 못한 것들을 제거하기 위한 최후의 노력으로 엉망진창인 것들을 치우는 것. 보통 우리는 무엇이 우리에게 닥칠지 몰랐기 때문입니다.우리는 항상 프로그램에서 어떤 종류의 데이터가 사용되는지 알아야 합니다. 예상치 못한/알 수 없는 데이터는 좋지 않습니다.제가 작업하는 배열에 있는 네일을 볼 때마다, 저는 왜 그것들이 존재하는지 알아보고 루비가 네일을 생성하는 시간과 메모리를 낭비하고 나중에 제거하기 위해 배열을 체로 걸러내는 대신, 어레이를 생성하는 코드를 개선할 수 있는지 알아봅니다.
'Just my $%0.2f.' % [2.to_f/100]
사용해 보십시오.reduce또는inject.
[1, 2, 3].reduce([]) { |memo, i|
if i % 2 == 0
memo << i
end
memo
}
안에 동의합니다.map그리고.compact하지만 같은 이유 때문은 아닙니다.
나는 그것을 깊이 느낍니다.map그리고나서compact는 와동합다니등다에 합니다.select그리고나서map 사항: 고려사:map는 일대일 함수입니다.만약 당신이 어떤 값들의 집합으로부터 매핑을 하고 있다면, 그리고 당신은map그런 다음 입력 집합의 각 값에 대해 출력 집합에 하나의 값을 입력합니다.만약 당신이 해야 하는 경우select사전에, 그렇다면 아마도 당신은 원하지 않을 것입니다.map촬영 중인만약 당신이 해야 하는 경우select에 (또는 에또나중는또()▁after에는orcompact) 그러면 아마 당신은 원하지 않을 것입니다.map어떤 두 번 할 때는 "" "" "" "" "" ""를 반복합니다.reduce한 번만 가면 됩니다.
또한 영어에서는 "정수 집합을 짝수 정수 집합으로 축소"하려고 합니다.
루비 2.7+
지금 있습니다!
Ruby 2.7은 다음과 같은 기능을 제공합니다.filter_map이 정확한 목적을 위하여그것은 관용적이고 실행적이며, 저는 그것이 곧 표준이 될 것이라고 기대합니다.
예:
numbers = [1, 2, 5, 8, 10, 13]
enum.filter_map { |i| i * 2 if i.even? }
# => [4, 16, 20]
이 경우 블록이 거짓으로 평가되므로 다음과 같이 간단히 수행합니다.
items.filter_map { |x| process_x url }
"Ruby 2.7 adds Enumerable #filter_map"은 이 문제에 대한 이전의 접근 방식에 대한 몇 가지 성능 벤치마크와 함께 이 주제에 대한 좋은 읽기입니다.
N = 100_000
enum = 1.upto(1_000)
Benchmark.bmbm do |x|
x.report("select + map") { N.times { enum.select { |i| i.even? }.map{ |i| i + 1 } } }
x.report("map + compact") { N.times { enum.map { |i| i + 1 if i.even? }.compact } }
x.report("filter_map") { N.times { enum.filter_map { |i| i + 1 if i.even? } } }
end
# Rehearsal -------------------------------------------------
# select + map 8.569651 0.051319 8.620970 ( 8.632449)
# map + compact 7.392666 0.133964 7.526630 ( 7.538013)
# filter_map 6.923772 0.022314 6.946086 ( 6.956135)
# --------------------------------------- total: 23.093686sec
#
# user system total real
# select + map 8.550637 0.033190 8.583827 ( 8.597627)
# map + compact 7.263667 0.131180 7.394847 ( 7.405570)
# filter_map 6.761388 0.018223 6.779611 ( 6.790559)
물론입니다compact이 작업을 해결하는 가장 좋은 방법입니다.그러나 간단한 뺄셈만으로 동일한 결과를 얻을 수 있습니다.
[1, nil, 3, nil, nil] - [nil]
=> [1, 3]
예를 들어, 다음과 같습니다.
items.map! { |x| process_x url } # [1, 2, 3, 4, 5] => [1, nil, 3, nil, nil]
값이 변경된 것처럼 보이지 않습니다.nil그렇다면 다음과 같습니다.
items.select{|x| process_x url}
충분할 것입니다.
예를 들어, 빈 문자열과 0을 거부하는 등 보다 느슨한 거부 기준을 원하는 경우 다음을 사용할 수 있습니다.
[1, nil, 3, 0, ''].reject(&:blank?)
=> [1, 3, 0]
더 나아가 0 값을 기각하려면(또는 더 복잡한 논리를 공정에 적용) 블럭을 통과시켜 기각할 수 있습니다.
[1, nil, 3, 0, ''].reject do |value| value.blank? || value==0 end
=> [1, 3]
[1, nil, 3, 0, '', 1000].reject do |value| value.blank? || value==0 || value>10 end
=> [1, 3]
사용할 수 있습니다.#compact결과 배열의 메서드입니다.
[10, nil, 30, 40, nil].compact => [10, 30, 40]
each_with_object가장 깨끗한 방법일 것입니다.
new_items = items.each_with_object([]) do |x, memo|
ret = process_x(x)
memo << ret unless ret.nil?
end
제 생각에는,each_with_object보다 낫습니다inject/reduce블록의 반환 값에 대해 걱정할 필요가 없기 때문에 조건부의 경우.
이를 위한 또 다른 방법은 아래와 같습니다.여기서, 우리는 값을 수집하고, 다른 방법으로 필요한 임시 변수를 제거하기 위해 사용합니다.nil를 확인합니다.process_x방법.
items.each_with_object([]) {|x, obj| (process x).tap {|r| obj << r unless r.nil?}}
그림의 전체 예:
items = [1,2,3,4,5]
def process x
rand(10) > 5 ? nil : x
end
items.each_with_object([]) {|x, obj| (process x).tap {|r| obj << r unless r.nil?}}
대체 접근 방식:
호하는방확인니다합을법출다▁by▁you니확▁are합인▁calling▁method▁looking▁at.process_x url입력의 .x런그식로으다음의가치처의 값을 하면, 약고가정다한면것라이할리를만당신.x그것을 조금 건네줌으로써.url그리고 다음 중 어떤 것을 결정됩니다.x정말로 유효한 비결정적 결과로 처리됩니다. 그렇다면, 아마도 더 나은 선택일 것입니다.Enumerable#map.
h = items.group_by {|x| (process x).nil? ? "Bad" : "Good"}
#=> {"Bad"=>[1, 2], "Good"=>[3, 4, 5]}
h["Good"]
#=> [3,4,5]
언급URL : https://stackoverflow.com/questions/13485468/how-to-map-and-remove-nil-values-in-ruby
'programing' 카테고리의 다른 글
| 부분 집합화된 데이터 프레임에서 사용되지 않는 요인 수준 삭제 (0) | 2023.06.27 |
|---|---|
| Application/font-woff2가 As를 사용할 때 작동하지 않습니다.Net VNext (0) | 2023.06.27 |
| .Net 대 SSIS:SSIS는 무엇에 사용되어야 합니까? (0) | 2023.06.27 |
| 오류 TS2345: 'T' 유형의 인수를 'object' 유형의 매개 변수에 할당할 수 없습니다. (0) | 2023.06.27 |
| macOS 터미널에서 파일 이름을 일괄 변경하는 방법? (0) | 2023.06.27 |