2016-01-02 2 views
-3

У меня есть файл file.txt, который имеет массив, который включает в себя хэшей:Как вставить хэш в массив

[{:name "Muhammad"},{:name "Mahmoud"}] 

Я пытаюсь читать по:

$list = File.readlines('file.txt') 

I затем добавить hash в массив:

$list << hash 

код работает, но он создает массив внутри массива:

["[{:name "/Mohammed/"},{:name "/Mahmoud/"}]"{:name "Ahmed"}] 

Когда я вместо того, чтобы прочитать файл с:

$list = File.read('file.txt') 

, а затем добавить hast [так в оригинале] в массив:

$list << hash 

Я на самом деле добавление hash в массив:

$list << hash 

Он дает эту ошибку:

can't convert Hash into String (TypeError) 

Как добавить хэш в массив?

+0

'[{: name" Muhammad "}, {: name" Mahmoud "}]' throws error (это не действительный Hash или Array), интересно, как работает этот код ... – karatedog

+0

Файл содержит только символы , без массивов или других объектов Ruby. Предположим, что эти символы - '' [{: name "Muhammad"}, {: name "Mahmoud"}] ''. Вы можете прочитать это в строке: 'str = File.read (file.txt) # =>" [{: name \ "Muhammad \"}, {: name \ "Mahmoud \"}] "'. (Нет глобальной переменной здесь, пожалуйста!). Если 'hash # => {: a => 1}', скажем, 'str << hash' поднимет указанное вами исключение, потому что аргумент' << ''должен быть строкой. –

+0

Serhat, вам нужно '[{: name =>« Muhammad »}, {: name =>« Mahmoud »}]' или '[{name:" Muhammad "}, {name:" Mahmoud "}]'. –

ответ

3

Вы неправильно поняли, что делают readlines и read, а также содержимое вашего файла. Начнем с таких вещей:

  1. Файлы не содержат массивов или хешей - они содержат текст, который, возможно, может быть проанализирован в массивы или хеши.
  2. File.read считывает содержимое файла в строку.
  3. File.readlines считывает содержимое файла в массив, содержащий строки, где каждая строка является одной строкой файла. Он (примерно) эквивалентен File.read('filename.txt').split("\n").

Итак, рассмотрим файл, который содержит (скорректированный на правильность синтаксиса Ruby)

[{name: "Muhammad"},{name: "Mahmoud"}] 

Хотя это выглядит вам нравится массив, содержащий хеши, скобки не имеют смысловое значение.Давайте прочитаем его:

> data = File.read('file.txt') 
=> "[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n" 

Примечание несколько вещей:

  • Есть цитаты, окружающие ваши данные - это строка
  • Кавычки в файле ("Muhammad") экранируются
  • Там представляет собой \n в конце строки, означая новую строку

Мы можем спросить data то, что она есть, и мы можем напечатать его, чтобы увидеть, что это действительно ваше содержимое файла без экранирования:

> data.class 
=> String 
> puts data 
[{name: "Muhammad"},{name: "Mahmoud"}] 
=> nil 

Теперь давайте попробуем File.readlines:

> lines = File.readlines('file.txt') 
=> ["[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n"] 

Примечание Кронштейнов окружающего ту же строку, которую мы имели до. Это массив, содержащий одну строку, которая была первой (единственной) строкой в ​​вашем файле.

> lines.class 
=> Array 
> lines.size 
=> 1 
> puts lines.first 
[{name: "Muhammad"},{name: "Mahmoud"}] 
=> nil 
> lines.first == data 
=> true 

Теперь мы можем перейти к ошибке, которую вы видите. Когда вы использовали readlines, а затем добавили hash, вы добавляли хэш в массив. Это совершенно законно в Ruby, потому что у вас могут быть массивы, содержащие элементы разных типов. Когда вы добавили hash, вы получили массив, содержащий строку и хэш.

> hash = {name: "Ahmed"} 
=> {:name=>"Ahmed"} 
> lines << hash 
=> ["[{name: \"Muhammad\"},{name: \"Mahmoud\"}]\n", {:name=>"Ahmed"}] 
> lines.map(&:class) 
=> [String, Hash] 
> lines.size 
=> 2 

Но, когда вы пытались добавить хэш результата read, вы добавить хэш строки, которая Руби не будет делать.

> data << hash 
TypeError: no implicit conversion of Hash into String 

Так, чтобы ответить на ваш вопрос в заголовке, вы можете добавить хэш в массив, вы просто не понимаете, что вы имели, и ваш массив первоначально не содержат данные, как вы ожидали его.

Чтобы прочитать ваш файл в виде массива Ruby, содержащего хеши, вы можете использовать eval, который выполняет строку, содержащую код Ruby. Это обычно не рекомендуется, потому что, например, если вы запустили его на данные, предоставленные другим пользователем, он может содержать код, который вы действительно не хотите выполнять. Поскольку вы управляете этим файлом, и это ваши собственные данные, в этом случае это достаточно безопасно.

> real_data = eval(File.read('file.txt')) 
=> [{:name=>"Muhammad"}, {:name=>"Mahmoud"}] 
> real_data.class 
=> Array 
> real_data.first 
=> {:name=>"Muhammad"} 
> real_data << hash 
=> [{:name=>"Muhammad"}, {:name=>"Mahmoud"}, {:name=>"Ahmed"}] 

Теперь у вас есть массив, содержащий рубин рубин хэш, и вы можете добавить еще один окрошку пути, который вы ожидаете.

+0

Я узнал так много вещей через ваш ответ, спасибо большое, мой код работает через использование eval. –

Смежные вопросы