2017-11-21 1 views
0

며칠 전이 같은 종류의 질문을했고 어떻게 든 통신이 이루어지지 않았습니다. 나는 나의 문제를 재구성하여 문제가 해결 될 수 있도록 노력하겠습니다.다른 열거 가능하지 않은 열거 가능한 클래스를 만드는 방법은 무엇입니까?

문제는 기본적으로 다음과 같습니다. 어떻게 다른 열거 형을 사용하지 않는 열거 형 클래스를 어떻게 만듭니 까? 단순화되었지만 제대로 작동하는 예제로서 다음 클래스를 고려하십시오.

class MyClass 
    include Enumerable 

    def get_next 
     return_val = rand.to_s 

     if return_val.match(/33/) 
      return nil 
     else 
      return return_val 
     end 
    end 

    def each 
     # ?????? 
    end 
end 

이 클래스에서 get_next는 임의의 값을 계산합니다. 그런 다음, 그 값이 두 개의 3을 서로 가지면,이 메소드는 nil을 리턴합니다. 그렇지 않으면 값을 리턴합니다. 그래서 당신은 10 개 이하의 시간을 위해 일반적으로, 반복 get_next 실행할 수 있습니다 데이터 포인트의 수천을 통해 검색 get_next 현실에서

myob = MyClass.new 

while not myob.get_next.nil? 
    puts 'got one' 
end 

을. 다음 항목을 찾으면 오히려 볼륨이 많은 객체를 반환합니다. MyClass 객체가 모든 항목에서 배열로 들어가는 것은 불가능합니다. 한 번에 하나씩 가져와야합니다.

실제로 클래스는 위와 같이 잘 작동합니다. 그러나이를 루비 같은 방법으로 구현하고 싶습니다.

위의 노동 계급이 주어지면 공란을 채우십시오. 이것을 열거 가능한 클래스로 만들기 위해 각() 안에 무엇이 들어가겠습니까?

+1

['Enumerator.new'] (http://ruby-doc.org/core-2.4.2/Enumerator.html # method-c-new) - 'take (10)'호출은 처음 10 개 항목 만 리턴한다. 그러나 숫자는 무한 루프에서 산출된다. 읽는 가치 : https://blog.arkency.com/2014/01/ruby-to-enum-for-enumerator/ – Stefan

답변

0
class MyClass 
    include Enumerable 

    def enum 
    @enum ||= Enumerator.new do |y| 
     loop do 
     value = get_next 
     raise StopIteration.new("nil") if value.nil? 
     y << value 
     end  
    end 
    end 

    def each 
    return enum_for(:each) unless block_given? 
    enum.each(&Proc.new) 
    end 

    def get_next 
    return_val = rand.to_s 
    return_val.match(/33/) ? nil : return_val 
    end 
end 

mc = MyClass.new 
mc.each { |e| puts e } 
#⇒ 0.9354594959902887 
# 0.6425492923024724 
# 0.24551401459676037 
# 0.17117672854168786 
# 0.15611540754420283 
# 0.3914491388594509 
# 0.40243662946930725 
# 0.3792875585148314 
# 0.11978219941961588 
# 0.49891129730441874 
+0

환상적인! 필요한만큼 일합니다. 감사! – tscheingeld

2

공란을 기입하십시오. 이것을 열거 가능한 클래스로 만들기 위해 각() 안에 무엇이 들어가겠습니까?

의사는 "The class must provide a method each, which yields successive members of the collection."라고 말합니다. 그래서 당신은 단지 그것을 할 수 있습니다, 그들은 nil이 아닌 한 항복 값을 유지하십시오.

def each 
    while val = get_next 
    yield val 
    end 
end 

데모 :

irb(main):002:0> MyClass.new.each { |e| puts e } 
0.9368650618038962 
0.9784286059513836 
0.9881624526762572 

또 다른 데모 (Enumerable에서하는 방법을 보여주기) :

irb(main):003:0> MyClass.new.map(&:to_f) 
=> [0.6368065208805999, 0.6926393662295052, 0.9911564544581742, 0.35788099831068787] 

그래서는 의미에서 '열거'만들기에 충분입니다 Enumerable에서 성공적으로 섞어서 (그리고 나는 공식적인 루비 정의가 "열거 가능"하다고 생각하지 않는다). 그것은 당신의 질문에서 당신이 실제로 그것을 필요로하는지 명확하지 않습니다, btw. 원하는 모든 값이 each으로 넘어가려면 Enumerable을 포함 할 필요가 없습니다. 모두가 mapselect과 같은 추가 방법을 제공합니다. 심지어 for 루프는 Enumerable 포함하지 않고, each 단지 덕분에 작동합니다

irb(main):002:0> for e in MyClass.new 
irb(main):003:1> puts e 
irb(main):004:1> end 
0.7638166357043203 
0.18409214000273166 
0.39757329498164495 
0.14658393540113002 
0.948396753859117 
0.3157122887487579 
0.4804571082701993 

(그러나 for 루프는 일반적으로 권장되지 않습니다 참고 :. [1], [2]을 나는 단지 더 each과의 중요성을 입증하기 위해이 보여주는거야 중요 반복을 위해 Enumerable의 중요하지 않음)

+0

... 만일'each'가 인자없이 (열거자를 반환하는 것처럼) (stdlib enumerables처럼) 반환하려면, 메소드의 맨 위로'block_given? '을 제외하고'return to_enum?'을 추가하십시오. – mwp

+0

이 구현은 반복 할 항목이 없을 때'StopIteration'이 _thrown_이 될 것으로 기대하는'next' contract과 호환되지 않습니다. 즉,이 구현은 루비와 전혀 호환되지 않으며 나중에 생산 런타임 버그로 판명 될 많은 숨겨진 결함이있을 수 있습니다. 적절한 방법은 '열거 자'입니다. 답안에 나타났습니다. 이것은 잘못되었거나 더욱 위험합니다. – mudasobwa

+0

@mudasobwa 응? 설명서에서 말하는대로 정확하게 작업하고 있습니다. 그리고 * "루비와 전혀 호환되지 않습니다"*? 내가 작동하는 부분을 간과 했습니까? * 데모에서는 '열거 형'의 어떤 것도 사용하지 않으므로 *보다 * 더 * 많이 할 수 있습니다. 그리고 "다음 계약"? 그것도 * 다음 방법을 가지고 * 않습니다. 그것은 열거 자입니다. 열거 형이 아닙니다. 그리고 만약 당신이 비 블록'Enumerator' 결과를 원한다면 mwp가 말한 것을 추가하십시오. 너는 너 자신을해라. 그 다음에'next'도있을 것이고'StopIteration'을 할 것입니다. 실제 문제를 보여줄 수 있습니까? –

관련 문제