문제

루비에서는 특정 요소가 수정되는 방식으로 배열을 매핑하는 가장 표현적인 방법은 무엇입니까? 그리고 다른 사람들은 손대지 않았다?

이것은 간단한 방법입니다.

old_a = ["a", "b", "c"]                         # ["a", "b", "c"]
new_a = old_a.map { |x| (x=="b" ? x+"!" : x) }  # ["a", "b!", "c"]

충분하지 않은 경우 "휴가"사례를 생략하십시오.

new_a = old_a.map { |x| x+"!" if x=="b" }       # [nil, "b!", nil]

내가 원하는 것은 다음과 같습니다.

new_a = old_a.map_modifying_only_elements_where (Proc.new {|x| x == "b"}) 
        do |y|
          y + "!"
        end
# ["a", "b!", "c"]

루비 에서이 작업을 수행 할 수있는 좋은 방법이 있습니까 (또는 레일에는 아직 찾지 못한 편의 방법이있을 수 있습니까?)?


답장 해 주셔서 감사합니다. 당신은 단지 사용하는 것이 최선이라고 총체적으로 설득했지만 map Ternary 운영자와 함께, 여러분 중 일부는 매우 흥미로운 답변을 게시했습니다!

도움이 되었습니까?

해결책

지도 문이 그대로 좋다는 데 동의합니다. 명확하고 단순하며 누구나 유지하기가 쉽습니다.

더 복잡한 것을 원한다면 이건 어때?

module Enumerable
  def enum_filter(&filter)
    FilteredEnumerator.new(self, &filter)
  end
  alias :on :enum_filter
  class FilteredEnumerator
    include Enumerable
    def initialize(enum, &filter)
      @enum, @filter = enum, filter
      if enum.respond_to?(:map!)
        def self.map!
          @enum.map! { |elt| @filter[elt] ? yield(elt) : elt }
        end
      end
    end
    def each
      @enum.each { |elt| yield(elt) if @filter[elt] }
    end
    def each_with_index
      @enum.each_with_index { |elt,index| yield(elt, index) if @filter[elt] } 
    end
    def map
      @enum.map { |elt| @filter[elt] ? yield(elt) : elt }
    end
    alias :and :enum_filter
    def or
      FilteredEnumerator.new(@enum) { |elt| @filter[elt] || yield(elt) }
    end
  end
end

%w{ a b c }.on { |x| x == 'b' }.map { |x| x + "!" } #=> [ 'a', 'b!', 'c' ]

require 'set'
Set.new(%w{ He likes dogs}).on { |x| x.length % 2 == 0 }.map! { |x| x.reverse } #=> #<Set: {"likes", "eH", "sgod"}>

('a'..'z').on { |x| x[0] % 6 == 0 }.or { |x| 'aeiouy'[x] }.to_a.join #=> "aefiloruxy"

다른 팁

배열은 포인터이기 때문에 다음에도 효과가 있습니다.

a = ["hello", "to", "you", "dude"]
a.select {|i| i.length <= 3 }.each {|i| i << "!" }

puts a.inspect
# => ["hello", "to!", "you!", "dude"]

루프에서 새 개체를 만드는 대신 개체를 변경하는 메소드를 사용해야합니다. 예를 들어 upcase! 비교 upcase.

정확한 절차는 정확히 달성하려는 것에 달려 있습니다. Foo-Bar 예제로 명확한 답을 못 박는 것은 어렵습니다.

old_a.map! { |a| a == "b" ? a + "!" : a }

주어진

=> ["a", "b!", "c"]

map! 수신기를 제자리에 수정합니다 old_a 이제 반환 된 배열입니다.

당신의 map 솔루션이 가장 좋습니다. 왜 당신이 MAP_MODIFYING_ONLY_ELEMENTS_가 어떻게 든 더 낫다고 생각하는지 잘 모르겠습니다. 사용 map 더 깨끗하고 간결하며 여러 블록이 필요하지 않습니다.

짧막 한 농담:

["a", "b", "c"].inject([]) { |cumulative, i| i == "b" ? (cumulative << "#{i}!") : cumulative }

위의 코드에서 [] "누적"으로 시작합니다. 열거 자 (우리의 경우 배열, [ "a", "b", "c"]를 통해 열거 할 때, 누적 및 "현재"항목은 우리 블록 (| 누적, i |)에 전달됩니다. 블록의 실행 결과는 누적에 할당됩니다. 위에서하는 일은 항목이 "B"가 아니고 "B!"를 부여 할 때 누적을 변경하지 않는 것입니다. 누적 배열을 위해 배열이 필요할 때 반환합니다. b.

위에 사용되는 답이 있습니다 select, 이것이 가장 쉬운 방법입니다.

당신은 결합 할 수 있습니다 select ~와 함께 map 찾고있는 것을 달성하기 위해 :

 arr = ["a", "b", "c"].select { |i| i == "b" }.map { |i| "#{i}!" }
 => ["b!"]

내부 select 블록, 요소가 "선택"할 조건을 지정합니다. 배열을 반환합니다. 결과 배열에서 "맵"을 호출하여 느낌표를 추가 할 수 있습니다.

이전 배열이 필요하지 않으면지도를 선호합니다! 이 경우 사용할 수 있기 때문에! 당신을 나타내는 메소드 배열을 제자리에 변경하고 있습니다.

self.answers.map!{ |x| (x=="b" ? x+"!" : x) }

나는 이것을 선호한다 :

new_map = self.old_map{ |x| (x=="b" ? x+"!" : x) }

몇 줄 길이이지만 여기에 대한 대안이 있습니다.

oa = %w| a b c |
na = oa.partition { |a| a == 'b' }
na.first.collect! { |a| a+'!' }
na.flatten! #Add .sort! here if you wish
p na
# >> ["b!", "a", "c"]

Ternary와의 수집은 제 생각에 가장 잘 보입니다.

이것을 달성하는 가장 좋은 방법은 사용하는 것입니다. tap

arr = [1,2,3,4,5,6]
[].tap do |a|
  arr.each { |x| a << x if x%2==0 }
end
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top