0

Currently I am getting an array of hashes by doing this:

f = File.open("public/odds/test.xml")
xml = Nokogiri::XML(f)
path = "//demo/test1/test"
xml.xpath(path).map do |x|
{'country' => x.parent}
end

A sample of my result for this:

[{"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"}]

Now as I have different xml files, I am doing a loop to go through all the files:

@files = ['a', 'b', 'c']
@files.each do |file|
f = File.open("public/odds/#{file}.xml)
xml = Nokogiri::XML(f)
path = "//demo/test1/test"
xml.xpath(path).map do |x|
{'country' => x.parent}
end

As it is looping through each file, I expect to get 3 different results like this [{"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"}]. How can I merge them together so that they are in 1 array?

1
  • Your code is invalid. Commented Oct 12, 2015 at 8:37

2 Answers 2

1

Do you want to inject results? Array#inject comes to the rescue:

path = "//demo/test1/test"
#      ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓
result = @files.inject([]) do |memo, file|
  File.open("public/odds/#{file}.xml") do |f|
    xml = Nokogiri::XML(f)
#   ⇓⇓⇓⇓⇓⇓⇓
    memo << xml.xpath(path).map do |x|
              {'country' => x.parent}
            end
  end
end.flatten
puts result
#⇒ [ {"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"},
#     ...
#     ... ]

Also, consider to use a File#open with a block. In your code the opened files remain unclosed, while the block will close them automatically on return. Whether one still wants to use File#new (≡ File#open without block,) one should explicitly call f.close as soon as the file is not needed anymore.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I would like to mark this as the correct answer, but I wonder why my result return as [ [{"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"}], [{"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"}],[{"country"=>"france"}, {"country"=>"singapore"}, {"country"=>"thailand"}]] ?
I used inject method along with flatten to solve my problem. Thanks
1

I think you try this way. just declare new array an push all hash inside that array arr << {'country' => x.parent} and replace your map by each loop

 arr=[]
    @files = ['a', 'b', 'c']
    @files.each do |file|
    f = File.open("public/odds/#{file}.xml)
    xml = Nokogiri::XML(f)
    path = "//demo/test1/test"
    xml.xpath(path).each do |x|
       arr << {'country' => x.parent}
    end
end

    return arr

4 Comments

i am considering it as function so return is used there. otherwise no need to used it. Just used arr variable
It is still ruby, not php. Function does not need to use return unless there is a quick-return pattern used for preliminary checks.
yes sure but i think more readble for OP so used return otherwise no need. here for more explanation to op so not using quick return.
Thanks. This is also a correct answer, but I chose to use the inject method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.