2013-07-29 2 views
0

У меня есть массив, который выглядит следующим образом:Последовательная разобрать массив хэш в Ruby,

array = [ 
    "timestamp 1", 
    "data 1", 
    "data 2", 
    "data 3", 
    "timestamp 2", 
    "data "1", 
    "timestamp 3", 
    ".." 
] 
    etc 

Я хочу проходным мой массив, и превратить его в структуру хеш данных, который выглядит как:

hash = { 
    "timestamp 1" => [ "data 1", " data 2", "data 3" ], 
    "timestamp 2" => [ "data 1" ], 
} 

Я не могу найти хороший «рубиновый» способ сделать это. Я перебираю массив, и я просто не могу понять, как отслеживать, где я нахожусь, и назначать хэш по мере необходимости.

# Let's comb through the array, and map the time value to the subsequent lines beneath 
array.each do |e| 
    if timestamp?(e) 
    hash["#{e}"] == nil 
    else 
    # last time stamp here => e 
end 

EDIT: Вот временная метка? Метод

def timestamp?(string) 
    begin 
    return true if string =~ /[a-zA-z][a-z][a-z]\s[a-zA-z][a-z][a-z]\s\d\d\s\d\d:\d\d:\d\d\s\d\d\d\d/ 
    false 
    rescue => msg 
    puts "Error in timestamp? => #{msg}" 
    exit 
    end 
end 
+0

Что '' метка времени делать? – sawa

+0

Просто функция, регулярное выражение которой определяет, является ли она допустимой меткой времени. Я обновляю сообщение с помощью функции. – awojo

+0

Ваш 'array' не является допустимым объектом Ruby. Проверьте седьмую строку. – sawa

ответ

2
array = [ 
    "timestamp 1", 
    "data 1", 
    "data 2", 
    "data 3", 
    "timestamp 2", 
    "data 1", 
    "timestamp 3", 
    "data 2" 
] 

hsh = {} 
ary = [] 

array.each do |line| 
    if line.start_with?("timestamp") 
    ary = Array.new 
    hsh[line] = ary 
    else 
    ary << line 
    end 
end 

puts hsh.inspect 
+0

Это сработало наилучшим образом! Благодаря! – awojo

+0

Я придаю большое значение читабельности. Спасибо, что выбрал мою из толпы. – Daiku

2

Я хотел бы сделать, как показано ниже:

array = [ 
    "timestamp 1", 
    "data 1", 
    "data 2", 
    "data 3", 
    "timestamp 2", 
    "data 1", 
] 

Hash[array.slice_before{|i| i.include? 'timestamp'}.map{|a| [a.first,a[1..-1]]}] 
# => {"timestamp 1"=>["data 1", "data 2", "data 3"], "timestamp 2"=>["data 1"]} 
0

Вы можете следить за последней хэш-ключа с помощью внешней переменной. Это будет сохраняться во всех итераций:

h = {} 
last_group = nil 
array.each do |e| 
    if timestamp?(e) 
    array[e] = [] 
    last_group = e 
    else 
    h[last_group] << e 
    end 
end 
0
last_timestamp = nil 
array.reduce(Hash.new(){|hsh,k| hsh[k]=[]}) do |hsh, m| 
    if m =~ /timestamp/ 
    last_timestamp = m 
    else 
    hsh[last_timestamp] << m 
    end 
    hsh 
end 
1
Hash[array.slice_before{|e| e.start_with?("timestamp ")}.map{|k, *v| [k, v]}] 

Выход

{ 
    "timestamp 1" => [ 
    "data 1", 
    "data 2", 
    "data 3" 
    ], 
    "timestamp 2" => ["data 1"], 
    "timestamp 3" => [".."] 
} 
0
hash = (Hash.new { |this, key| this[key] = [] }).tap do |hash| 
    current_timestamp = nil 
    array.each do |element| 
    current_timestamp = element if timestamp? element 
    hash[current_timestamp] << element unless timestamp? element 
    end 
end 

Использование внешней переменной для отслеживания текущего времени, но завернув в закрытии, чтобы избежать загрязнения пространства имен.

0

Я знаю, что на это уже был дан ответ, но есть так много способов сделать это.

Я предпочитаю эти два пути, они не могут быть быстро, но я нахожу их читаемыми:

my_hash = Hash.new 
array.slice_before(/timestamp/).each do |array| 
    key, *values = array 
    my_hash[key] = values 
end 

или

one_liner = Hash[array.slice_before(/timestamp/).map{|x|[x.shift, x]}] 
Смежные вопросы