2017-05-05 1 views
1

누산기를 사용할 때 누산기는 reduce 블록 내에 만 존재합니까? 아니면 함수 내에 있습니까?정의되지 않은 변수를 가져 오지 않고 Ruby에서 reduce/inject를 사용하는 방법

나는처럼 보이는 방법이 : 나는이 코드를 실행하면 나는 오류를 얻을

def my_useless_function(str) 
    crazy_letters = ['a','s','d','f','g','h'] 
    str.split.reduce([]) do |new_array, letter| 
    for a in 0..crazy_letters.length-1 
     if letter == crazy_letters[a] 
     new_array << letter 
     end 
    end 
    end 

    return true if (new_array == new_array.sort) 
end 

을 나는 또한 내부 else 문 같은 다른 변수에 new_array 값을 할당하려고

"undefined variable new_array in line 11 (the return statement)" 

reduce 블록하지만 그게 나에게 동일한 결과를 줬다.

왜 이런 일이 일어 났는지 설명 할 수 있습니까?

답변

2

블록의 지역 변수

new_array

reduce 전화의 블록 밖에 존재하지 않습니다. "block local variable"입니다.

reduce 개체를 반환하지만 사용자의 메서드 내에서 사용해야합니다.

def my_useless_function(str) 
    crazy_letters = ['a','s','d','f','g','h'] 
    new_array = str.split(//).reduce([]) do |new_array, letter| 
    for a in 0..crazy_letters.length-1 
     if letter == crazy_letters[a] 
     new_array << letter 
     end 
    end 
    new_array 
    end 

    return true if (new_array == new_array.sort) 
end 

참고 :

  • return가 마지막에 필요하지 않은

    sum = [1, 2, 3].reduce(0){ |acc, elem| acc + elem } 
    puts sum 
    # 6 
    puts acc 
    # undefined local variable or method `acc' for main:Object (NameError) 
    

    귀하의 코드

    여기에 당신의 방법에 대한 변화의 최소 금액입니다.

  • true if ...는 하나
  • for 루프 블록 내부의 마지막 식의 결과를 반환
  • reduce 루비
  • 사용해서는 안됩니다 필요하지 않습니다. 코드에 for이었습니다.
  • 항상 동일한 객체를 reduce에 반환해야하는 경우 each_with_object을 사용할 수있는 기호 일 수 있습니다.
  • "test".split["test"]

StringEnumerable 당신을 도울 수있는 방법이 있습니다. 그것들을 사용하면 @Phrogz answer에서와 같이 훨씬 더 깔끔하고 효율적인 방법을 쓸 수 있습니다.

3

reduce을 호출하는 동안 new_array이 만들어지고 나중에 참조가 손실된다는 문제가 있습니다. 루비의 지역 변수는 자신이 속한 블록으로 범위가 지정됩니다. 배열은 케이스에 reduce에서 반환 될 수 있으므로 거기에 사용할 수 있습니다. 그러나 몇 가지 문제를 해결해야합니다.

  • str.split Ruby 2 이상에서는 문자열을 문자로 구분하지 않습니다. str.chars 또는 str.split('')을 사용해야합니다.
  • reduce의 새 반복마다 유지되는 개체는 매번 블록에서 반환하여 유지해야합니다. 가장 간단한 방법은 new_array을 블록의 마지막 표현식으로 사용하는 것입니다. 따라서

: 함수가 매우 관용적 매우 효율적인, 그리고하지

def my_useless_function(str) 
    crazy_letters = ['a','s','d','f','g','h'] 
    crazy_only = str.split('').reduce([]) do |new_array, letter| 
    for a in 0..crazy_letters.length-1 
     if letter == crazy_letters[a] 
     new_array << letter 
     end 
    end 
    new_array 
    end 

    return true if (crazy_only == crazy_only.sort) 
end 

참고. 더 효율적 버전

def my_useless_function(str) 
    crazy_letters = %w[a s d f g h] 
    crazy_only = str.chars.select{ |c| crazy_letters.include?(c) } 
    crazy_only == crazy_only.sort # evaluates to true or false 
end 

을 그리고 다음과 같습니다 : 여기에 있지 훨씬 더 효율적으로 더 관용적 인 기능의 짧은 버전,하지만

def efficient_useless(str) 
    crazy_only = str.scan(/[asdfgh]/) # use regex to search for the letters you want 
    crazy_only == crazy_only.sort 
end 
+2

니스, 나는 더 효율적인 버전을 기록하고 있었다 그러나 그것은 당신과 매우 유사했을 것입니다. 배열이 정렬되어 있는지 확인하려면 정렬 할 필요가 없습니다 (예 :'each_cons'를 대신 사용할 수 있습니다) –

+0

@Eric, 아마도 Ruby는'class Array; def sorted? : enum = self.to_enum; loop {return false if (enum.next <=> enum.peek) == 1}; 참된; 종료; 종료; [1,2,3]. 정렬? # => true; [1,3,2]. 정렬? # => false' (또는 제안한대로'each_cons'를 사용하십시오). –

+2

@CarySwoveland :'Array # sorted? '는 기본 루프가있는 C 함수의 완벽한 후보가 될 것입니다. –

관련 문제