2014-04-03 2 views
0

코드와 관련된 용어로 파일을 열려고합니다. 파일의 한 줄은 다음과 같이 나타납니다.해시에서 문자열 값을 연결하는 방법

Pacific Ocean; D01.330.322 

해시로 표시하고 싶습니다. 일부 용어는 두 번 이상 나타나며 그 값을 ","에 의해 결합 된 하나의 문자열에 넣고 싶습니다. 내가 가진 코드는 다음과 같습니다

descriptor_code_hash = Hash.new 
File.open('mtrees2014.bin').each do |file_line| 
    file_line = file_line.chomp 
    mesh_descriptor, tree_code = file_line.split(/\;/) 
    descriptor_code_hash[mesh_descriptor] = tree_code 
    if descriptor_code_hash.has_key? mesh_descriptor 
    tree_code << "," << tree_code 
    else 
    descriptor_code_hash[mesh_descriptor] 
    end 
end 

용어가 여러 개의 코드를 가지고

는 동일한 코드는 한 번에 연결됩니다 및 용어에 대한 기타 고유 코드는 식별되지 않습니다. 또한, 모든 코드를 얻기 위해 스크립트를 작성하는 방법을 모르겠습니다. 예를 들어, 일부 용어에는 6 개의 코드가 있습니다.

+0

코드의 배열 대신 코드가 쉼표로 구분되기를 원하는 이유가 있습니까? – BroiSatse

+0

관련 코드를 식별하기 위해 파일의 특정 용어에서 각 코드를 사용해야합니다. 문자열을 분리하고 각 코드를 쉽게 얻을 수 있다고 생각했습니다. 나는 각각의 값이 값의 배열 인 해시를 사용한 적이 없다. 당신이 그 전략에 익숙하다면 당신의 아이디어를 환영 할 것입니다! – user3385593

+0

당신이 "다른 대답을 읽었지만" "내 질문에는 아무도 대답하지 못했다"라고 말하면 이미 시도한 ***에 대한 답변을 알려주는 데 도움이됩니다. **), 그래서 우리는 똑같은 대답을 반복하지 않게됩니다. 왜냐하면 그것은 단지 *** 모든 사람의 시간, 우리와 당신의 시간을 낭비하기 때문입니다. –

답변

0

시도 :

descriptor_code_hash = Hash.new 
File.open('mtrees2014.bin').each do |file_line| 
    file_line = file_line.chomp 
    mesh_descriptor, tree_code = file_line.split(/\;/) 
    (descriptor_code_hash[mesh_descriptor] ||= []) << tree_code 
end 

이 방법 descriptor_code_has[key] 주어진 키를 사용하여 파일의 모든 코드가있는 배열입니다.

+0

답변 해 주셔서 감사합니다. @BroiSatse! 이 코드를 실행하고 "="을 제거 할 때까지 오류가 발생했습니다. 이 스크립트는 키/값 쌍의 목록을 만들었지 만, 값을 배열로 보지 않았습니다. 올바르게 보지 않는 한. 나는 다음을 사용했다 : "기술자 : # {mesh_descriptor}와 그 코드 : # {tree_code}"를 넣는다. 그 결과 해시에서 완전한 목록을 얻었지만 문자열이나 배열로 그룹화 된 코드는 없습니다. 더 이상의 생각? 고맙습니다! – user3385593

+0

@ user3385593 - 어떤 종류의 오류가 발생 했습니까? 위의 코드에서 안전하게 제거 할 수있는'= '은 없습니다. – BroiSatse

+0

안녕하세요 @ BroiSatse!, 내가 가진 오류는 "예기치 못한"이었습니다.문자열에서 "="을 제거하면 스크립트가 정상적으로 실행되었지만 연결된 코드가 반환되지 않았습니다. – user3385593

1

코드가 멀리 떨어져 있지 않습니다. 그것을 통해 가자.

테스트 데이터는 다음 테스트에 사용하기 위해 일부 데이터입니다 : 내가 문자열 배열에서 읽어 물건을 단순화

oceans = ["Pacific; 1", "Atlantic; 2", "Indian; 3", 
      "Pacific; 2", "Atlantic; 1", "Pacific; 3"] 

오히려 파일의 라인을 읽는 것보다. 코드가 작동하면 파일에서 읽기 쉽게 변경할 수 있습니다. 이제 우리는 어떤 입력 데이터를 가지고

, 우리는 우리가 예상 한 결과이 원하는 것을 보여줄 수 있습니다

hash = 
    { 'Pacific' => ['1', '2', '3'], 
    'Atlantic' => ['2', '1'], 
    'Indian' => ['1'] } 

또는

hash = 
    { 'Pacific' => "'1', '2', '3'", 
    'Atlantic' => "'2', '1'", 
    'Indian' => "'1'" } 

는 가장 쉬운 방법으로 우리는 첫 번째를 사용합니다 우리가 두 번째 형식을 원하면 처음부터 쉽게 계산할 수 있습니다.

hash.keys.each { |k| hash[k] = hash[k].join(',') } 
    #=> ["Pacific", "Atlantic", "Indian"] 

그러나 기다림, tha t는 반환 된 해시가 아닙니다. 아니요, hash.keys입니다. 이외에도

hash #=> {"Pacific"=>"1,2,3", "Atlantic"=>"2,1", "Indian"=>"1"} 

: 우리가 원하는 것은 hash의 새로운 값 질문을 게시하는 경우에 따라서는 예상 된 결과와 함께 약간의 설명을 입력 데이터를 포함하는 것이 도움이됩니다. 그것은 명확하고 단어를 저장하는 경향이 있습니다. 가능한 한 적은 데이터로 사용해보십시오.

코드는

다음 코드는 파일의 읽기 대체 배열 oceans로,이다는 :

descriptor_code_hash[mesh_descriptor] = tree_code 

각 :

descriptor_code_hash = Hash.new 
oceans.each do |file_line| 
    file_line = file_line.chomp 
    mesh_descriptor, tree_code = file_line.split(/\;/) 
    descriptor_code_hash[mesh_descriptor] = tree_code 

    if descriptor_code_hash.has_key? mesh_descriptor 
    tree_code << "," << tree_code 
    else 
    descriptor_code_hash[mesh_descriptor] 
    end 
end 

가장 큰 문제는 라인 루프를 통과 할 때 mesh_descriptordescriptor_code_hash 값이 res입니다. 현재 (파일의 행을 나타냄)의 요소에 대해 tree_code의 값으로 변경합니다. 이 행을 삭제해야합니다. 우리가 이것을 실행하면

descriptor_code_hash = Hash.new 
oceans.each do |file_line| 
    file_line = file_line.chomp 
    mesh_descriptor, tree_code = file_line.split(/\;/) 
    if descriptor_code_hash.has_key? mesh_descriptor 
    descriptor_code_hash[mesh_descriptor] << tree_code 
    else 
    descriptor_code_hash[mesh_descriptor] = [tree_code] 
    end 
end 

, 우리가 얻을 :

descriptor_code_hash 
    #=> {"Pacific"=>[" 1", " 2", " 3"], "Atlantic"=>[" 2", " 1"], 
    # "Indian"=>[" 3"]} 

if descriptor_code_hash.has_key? mesh_descriptor 
    descriptor_code_hash[mesh_descriptor] << tree_code 
else 
    descriptor_code_hash[mesh_descriptor] = [tree_code] 
end 

이 다음 당신에게 제공 : 다음과 같이

다음으로, 우리는 당신의 if/else/end 문을 변경해야

작은 포맷 문제가 있다는 것을 제외하면 결과가 정확합니다. 우리는 변화에 의해 그 문제를 해결할 수 있습니다 :

file_line.split(/\;/) 

두 가지 방법으로 간단하게 할 수있는

file_line.split(/\;/).map { |w| w.strip } 

에 :

file_line.split(';').map(&:strip) 

것은 그것을 시도하자. 한다고 가정

file_line = "Pacific; 1\n" 

그럼

file_line.split(';').map(&:strip) #=> ["Pacific", "1"] 

원하는 결과이다. 문자열 끝에 줄 바꿈 문자가 포함되어 있음을 주목하십시오. 그것은 strip이 공백뿐만 아니라 그것을 제거한다는 것을 보여줍니다. 즉, 이전 줄 필요가 없습니다 의미 : (. file_line.chomp.split(/\s*;\s*/)도 작동)

file_line = file_line.chomp 

귀하의 코드는 지금까지 간체된다

descriptor_code_hash = Hash.new 
oceans.each do |file_line| 
    mesh_descriptor, tree_code = file_line.split(';').map(&:strip) 
    if descriptor_code_hash.has_key? mesh_descriptor 
    descriptor_code_hash[mesh_descriptor] << tree_code 
    else 
    descriptor_code_hash[mesh_descriptor] = [tree_code] 
    end 
end 

연마 이제 루비와 같은 코드를 만들기 위해 할 수있는 일을 생각해보십시오. 첫째, (당신의 if/else/end 구조 대신에) @BroiSatse에 의해 주어진 답에 사용 된 다음 줄에 보면 : 어떤 변수 a를 들어

(descriptor_code_hash[mesh_descriptor] ||= []) << tree_code 

a ||= []a = (a || [])과 동일합니다.a이 정의되어 있지 않으면 nil과 같으므로 (nil || []) => []이됩니다. a에 (0이 아닌) 값이 지정되면 (a || []) => a. 즉, descriptor_code_hashmesh_descriptor (의미 : descriptor_code_hash[mesh_descriptor] => nil) 키가없는 경우 descriptor_code_hash[mesh_descriptor][]이 할당됩니다. 그렇지 않으면 자체적으로 할당됩니다 (즉 변경되지 않음).

descriptor_code_hash[mesh_descriptor] ||= [] 

실행

descriptor_code_hash[mesh_descriptor] 빈 또는 다른 배열을 같게한다. << tree_code 다음 해시 값 (배열)에 tree_code을 추가합니다. 마지막으로 대신 {}을 사용할 수 있지만 그만의 문체가 있습니다.

귀하의 코드는 이제 다음과 같습니다

descriptor_code_hash = {} 
oceans.each do |file_line| 
    mesh_descriptor, tree_code = file_line.split(';').map(&:strip) 
    (descriptor_code_hash[mesh_descriptor] ||= []) << tree_code 
end 

의 지금이 방법을 만들어 보자하고 몇 가지 더 변경합니다, 나는 변수 이름의 일부를 단순화했습니다

def descriptor_code_hash(oceans) 
    oceans.each_with_object({}) do |line, hash| 
    mesh_descriptor, tree_code = line.split(';').map(&:strip) 
    (hash[mesh_descriptor] ||= []) << tree_code 
    end 
end 

descriptor_code_hash(oceans) 
    #=> {"Pacific"=>["1", "2", "3"], "Atlantic"=>["2", "1"], "Indian"=>["3"]} 

을하기 때문에 메소드의 목적은 이름으로 설명됩니다. 사용 방법을 보려면 Enumerable#each_with_object (버전 1.9부터 사용 가능)에 대한 문서를 읽어보십시오.

아마 메소드 인수로 파일 이름을 원할 것입니다.

마지막으로 한가지 :

여기
def descriptor_code_hash(oceans) 
    oceans.each_with_object(Hash.new {|k,h| h[k] = {} }) do |line, hash| 
    mesh_descriptor, tree_code = line.split(';').map(&:strip) 
    hash[mesh_descriptor] << tree_code 
    end 
end 

객체가 초기화되는 : 다음과 같이 당신이 대신 쓸 수있는 새 키를 추가 할 때의 기본값 (수

Hash.new {|k,h| h[k] = {} } 

해시에) 빈 해시. 3 번째 줄부터 마지막 ​​줄까지 그림과 같이 단순화 할 수 있습니다.

+0

와우 캐리! 지난 3 개월 동안 수업에서 얻은 것보다 루비에 대한 답을 더 많이 배웠습니다. 매우 상세하고 포괄적 인 답변을 해주셔서 감사합니다! 귀하의 제안을 제 코드에 적용 해 보겠습니다. 고맙습니다! – user3385593

+0

친절한 단어를 가져 주셔서 감사합니다. 도와 줘서 기뻐. –