2017-01-06 2 views
1

Вот пример массива Я работаю с:Конкатенации существующих значений в пределах одного массива в Рубине

arr = [ "id1", "name1", "id2", "name2", "id3", "name3" ] 

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

new_arr = [ "id1: name1", "id2: name2", "id3: name3" ] 

Моя попытка:

ids = arr.select.with_index { |_, i| i.even? } 
names = arr.select.with_index { |_, i| i.odd? } 
new_arr = ids.map { |i| i + ": " + names[ids.index(i)] } 

есть ли лучше или более выразительный способ сделать это (возможно в однострочника)?

+0

являются идентификаторами уникальным? –

+0

Да, идентификаторы уникальны и всегда входят в этот идентификатор, шаблон имени для массива. – massaskillz

+0

Тогда вам может быть интересно использовать хэш, 'arr.each_slice (2) .to_h # => {" id1 "=>" name1 "," id2 "=>" name2 "," id3 "=>" name3 " } 'для удобного доступа к значениям с использованием обычной хэш-функции [key]. –

ответ

3

Я хотел бы использовать each_slice и интерполяцию строки.

arr.each_slice(2).map { |(a, b)| "#{a}: #{b}" } 
#=> ["id1: name1", "id2: name2", "id3: name3"] 

Ричард Hamilton`s комментарий заставил меня думать о выполнении различных решений:

require 'benchmark' 

arr = [ "id1", "name1", "id2", "name2", "id3", "name3" ] 
slices = arr.each_slice(2) 

n = 1_000_000 

Benchmark.bmbm(15) do |x| 
    x.report("hashified  :") { n.times do; Hash[*arr].map { |e| e.join ': ' } ; end } 
    x.report("concatenation :") { n.times do; slices.map { |a| a[0] + ": " + a[1] } ; end } 
    x.report("array join :") { n.times do; slices.map { |a| a.join(': ') }  ; end } 
    x.report("interpolated :") { n.times do; slices.map { |(a, b)| "#{a}: #{b}" } ; end } 
end 

# Rehearsal --------------------------------------------------- 
# hashified  : 3.520000 0.030000 3.550000 ( 3.561024) 
# concatenation : 2.300000 0.010000 2.310000 ( 2.315952) 
# array join : 3.020000 0.010000 3.030000 ( 3.032235) 
# interpolated : 1.950000 0.000000 1.950000 ( 1.954937) 
# ----------------------------------------- total: 10.840000sec 
# 
#      user  system  total  real 
# hashified  : 3.430000 0.040000 3.470000 ( 3.473274) 
# concatenation : 2.320000 0.010000 2.330000 ( 2.332920) 
# array join : 3.070000 0.010000 3.080000 ( 3.081937) 
# interpolated : 1.950000 0.000000 1.950000 ( 1.956998) 
+0

Все производные 'each_slice' имеют один и тот же сбой: не будет терпеть нечетное количество элементов. – mudasobwa

+0

Не все * производные: Моя версия поднимет ошибку на нечетное число элементов из-за части '(a, b)'. – spickermann

+0

А, действительно, извините. Правильно. Upvoted. – mudasobwa

1

each_slice Попробуйте использовать:

arr.each_slice(2).entries.map { |ar| ar.join(': ') }      
#=> ["id1: name1", "id2: name2", "id3: name3"] 
+0

' entries' здесь лишний. См. Другие ответы. –

2

Вы можете использовать Enumerable «ы each_slice метод, чтобы получить перечисление 2-элементных массивов с вашего arr. Вы можете просто join эти элементы:

arr.each_slice(2).map{|a| a.join(': ')} 

Что здесь происходит это each_slice возвращает Enumerator, который дает 2-элементные массивы. Так как Enumerator s также являются Enumerable, вы можете просто использовать map, чтобы изменить эти 2-элементные массивы и join их на строку.

+0

Я не думал об использовании 'join'. Это делает его более эффективным, чем мой ответ –

1

Вы должны использовать each_slice для этого

arr.each_slice(2).map { |a| a[0] + ": " + a[1] } 
=> ["id1: name1", "id2: name2", "id3: name3"] 
+0

'a.first' и' a.last' могут быть использованы здесь. –

2

each_slice глупо :)

Hash[ "id1", "name1", "id2", "name2", "id3", "name3" ]. 
    map { |e| e.join ': ' } 
#⇒ [ "id1: name1", "id2: name2", "id3: name3" ] 
+0

Это прерывается, если у вас есть дубликаты «ids». –

+0

@HolgerJust Вот почему я думаю, что это решение на самом деле лучше. – mudasobwa

+1

Вы считаете, что ваше решение лучше, потому что оно ломается на кромках? Это ... необычное мнение. –

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