- Сообщений: 247
- Спасибо получено: 537
array tricks
11 года 8 мес. назад - 11 года 8 мес. назад #72989
от Iren_Rin
Iren_Rin создал тему: array tricks
На мой взгляд работа с массивами - одна из самых сильных сторон руби. С ними можно cделать вообще все что пожелаешь. Тут я хочу привести пример тех полезных методов и трюков, которые я использую чуть ли не каждый день. Я опущу совсем уж банальщину типа <<. Прошу опытный рубистов не кидать в меня помидорами, тема больше для неопытных
Почти все методы не изменяют начальный массив, но у многих есть бенг вариант (c ! на конце), который это делает. Это называется side effect (неприятная штука, если ей злоупотреблять).
Операции над массивами, они очень быстрые и главное мощные:
Про сложение знают наверное все
Вычитание тоже очень полезно (например для валидации с запрещенными элементами).
Пересечение массивов - когда есть массив с разрешенными элементами, и массив, который нужно очистить. Очень часто использую.
Объединение. Работает примерно так - складывает два массива, потом идет по новому массиву и выкидывает все элементы, которые встречал раньше.
C умножением будьте осторожны, на самом деле элементы не множатся а множится ссылка на них.
Работа с индексами не такое уж и тривиальное занятие.
Получить подмасив:
То что совсем не очевидно на первый взгляд, но очень полезно - замена при помощи индексов
Array#map - рабочая лошадка, когда из одного массива нужно получить другой массив, связанный с первым.
Array#select, Array#reject - исполняют блок для каждого элемента массива, если блок возвращает истину то первый оставляет элемент в новом массиве, второй - наоборот выкидывает. Оба имеют bang аналоги, используйте с умом
Array#inject - очень мощная вещь, очень часто использую. Позволяет пройтись по массиву, с каждым элементом выполнить блок и сохранить результат по всему стеку.
Если вы завели переменную-массив, и заполняете ее во время перебора, то скорее всего вам нужен inject.
Array#compact - приятный метод, который просто удаляет все nil из массива.
Array#flatten - мой любимец
Разворачивает массив любой вложенности в простой массив:
Я сам удивляюсь на сколько часто я использую flatten. Он более полезный, чем может показаться.
Array#empty? - возвращает true когда в массиве ничего нет
Array#any? - возвращает true когда в массиве что нибудь есть.
Array#find - применяет блок к каждому элементу пока он не вернет истину. Когда истина получена - возвращает текущий элемент
#with_index - позволяет к любому итератору подмешать индекс текущего элемента:
Array#sample возвращает случайный элемент массива, или несколько уникальных случайных элементов, если передали параметр
Array#uniq - если хотите получить массив уникальных значений
Array#join приводит каждый элемент в строку, потом соединяет полученные строки через строку-аргумент.
И последний который я сегодня упомяну - sort. Без блока он просто сортирует массив. С блоком его используют, когда нужно как то по сложному отсортировать массив. В блок передаются по два элемента. Метод ожидает от блока один из трех вариантов = -1 когда левый элемент меньше правого, 0 - когда элементы равны, +1 - когда левый элемент больше правого.
Получилось многовато, надеюсь эта стена текста была полезна кому нибудь. Удачи!
Почти все методы не изменяют начальный массив, но у многих есть бенг вариант (c ! на конце), который это делает. Это называется side effect (неприятная штука, если ей злоупотреблять).
Операции над массивами, они очень быстрые и главное мощные:
Про сложение знают наверное все
Code:
[1, 2] + [3, 4] #=> [1, 2, 3, 4]
Code:
[3, 4, 5] - [4, 5] #=> [3] Удаляет из первого массива все элементы второго массива. (Не изменяет изначальный массив, возвращает копию)
Code:
[1, 2, 3] & [2, 3] # => [2, 3] Вернет новый массив с элементами которые встречаются в обоих массивах.
Code:
[1, 2, 3, 3] | [2, 4, 5] # => [1, 2, 3, 4, 5]
C умножением будьте осторожны, на самом деле элементы не множатся а множится ссылка на них.
Code:
[ Object.new ] * 4 #Создаст массив с 4 ссылками на один объект
Array.new(4) { Object.new } # Чаще всего когда умножают массив - хотят именно такой результат.
# 4 раза выполни блок, результат сохрани в новый массив.
Работа с индексами не такое уж и тривиальное занятие.
Получить подмасив:
Code:
[1, 2, 3, 4, 5, 6][2 .. 4] #=> [3, 4, 5] Две точки включают последний элемент
[1, 2, 3, 4, 5, 6][2 ... 3] #=> [3, 4] Три точки - не включают, кстати 2 .. 3 - это Range, а не магия :)
[1, 2, 3, 4, 5][3 .. 1] #А это не сработает, когда хотите перевернутую часть массива делайте так:
[1, 2, 3, 4, 5][1 .. 3].reverse
Code:
arr = [1, 2, 3, 4, 5]
arr[2 .. 3] = 'x' #Возьми элементы со второго по третий и замени их на x
arr # => [1, 2, 'x', 5]
arr[0 .. 1] = ['y', 'y', 'y'] #Возьми элементы с первого по второй и замени их на новый массив ( при этом, как ни странно, новый массив не будет одним элементом, он вставится и развернется)
arr # => ['y', 'y', 'y', 'x', 5]
arr[1 ... 2] = ['z', 'z'] #Возьми элементы со второго по третий (не включая, т.е. только второй) И замени их на новый массив.
arr # => ['y', 'z', 'z', 'y', 'x', 5]
arr[0 .. 1] = [] #Удали элементы 0 и 1
arr # => ['z', 'y', 'x', 5]
arr[1 ... 1] = ['i', 'i'] #Вставь после первого элемента новый массив.
arr # => ['z', 'i', 'i', 'y', 'x', 5]
Array#map - рабочая лошадка, когда из одного массива нужно получить другой массив, связанный с первым.
Code:
numbers = [18, 13, 14, 15]
numbers.map { |i| "i + 3 = #{i + 3}" } #map выполняет блок для каждого элемента массива, результат становится элементом нового масива
Code:
[1, 2, 3, 4].select { |i| i > 2 } #=> [3, 4]
[1, 2, 3, 4].reject { |i| i > 2 } #=> [1, 2]
Code:
arr = [1, 2, 3, 4, 5, 6, 7]
#Метод принимает один аргумент, который будет начальным значением
arr.inject 0 do |sum, element| #В блок передается результат по стеку и текущий элемент
if element % 2 == 0
sum + element #Вы можете не изменять значение sum, все равно в следующий блок
else #передастся результат исполнения предыдущего
sum #(последнее выражение в предыдущем блоке)
end
end # => В итоге получим сумму всех четных элементов.
Array#compact - приятный метод, который просто удаляет все nil из массива.
Code:
[1, nil, nil, 2, 3, nil].compact # => [1, 2, 3]
# недавно игрался с мейкером -
$game_party.line_set.slots.map(&:buttler).compact # тут с map используется краткий синтаксис блоков, могу и про это рассказать как-нибудь.
Array#flatten - мой любимец
Code:
[1, [2, [3]], 4].flatten #[1, 2, 3, 4]
Array#empty? - возвращает true когда в массиве ничего нет
Array#any? - возвращает true когда в массиве что нибудь есть.
Code:
[1, 2, 3, 4, 5, 6].any? { |i| i > 2 } #Такой синтаксис any? применяет к каждому элементу блок,
#пока блок не вернет истину (не nil или false).
#Тогда и any? вернет true
Array#find - применяет блок к каждому элементу пока он не вернет истину. Когда истина получена - возвращает текущий элемент
Code:
[1, 2, 3, 4, 5, 6].find { |i| i > 3 } # => 4. До 5 и 6 он не доберется.
#with_index - позволяет к любому итератору подмешать индекс текущего элемента:
Code:
#Это можно использовать к примеру в параллельном переборе
arr1 = [2, 3]
arr2 = [4, 5]
arr1.each.with_index do |element, index|
puts element
puts arr2[index]
end
Array#sample возвращает случайный элемент массива, или несколько уникальных случайных элементов, если передали параметр
Code:
arr = [1, 2, 3, 4, 5]
arr.sample # => 3
arr.sample(3) # => [1,3,4]
Array#uniq - если хотите получить массив уникальных значений
Array#join приводит каждый элемент в строку, потом соединяет полученные строки через строку-аргумент.
Code:
arr = [1, 2, 3]
"#{arr.join(' + ')} = #{arr.inject(0) { |s, i| s + i }}" #=> "1 + 2 + 3 = 6"
И последний который я сегодня упомяну - sort. Без блока он просто сортирует массив. С блоком его используют, когда нужно как то по сложному отсортировать массив. В блок передаются по два элемента. Метод ожидает от блока один из трех вариантов = -1 когда левый элемент меньше правого, 0 - когда элементы равны, +1 - когда левый элемент больше правого.
Code:
arr = [1, 2, 3, 4, 5, 6, 7, 8] # отсортируем его так - сначала четные, потом нечетные
arr.sort { left, right| left % 2 - right % 2 } #[8, 2, 6, 4, 5, 3, 7, 1]
Получилось многовато, надеюсь эта стена текста была полезна кому нибудь. Удачи!
Последнее редактирование: 11 года 8 мес. назад пользователем Iren_Rin.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
11 года 8 мес. назад #73011
от Iren_Rin
Iren_Rin ответил в теме array tricks
Приведу пример использования inject
Допустим есть такой массив
Тут первый элемент - валюта, второй - количество денег в этой валюте. Из этого массива мы хотим получить хэш, где ключ будет - валюта, значение - сумма всех денег по этой валюте.
Можно сделать так:
А можно сделать так:
Простой пример - сумма всех элементов в массиве
Допустим есть такой массив
Code:
arr = [['EUR', 100], ['USD', 50], ['EUR', 200], ['USD', 150]]
Можно сделать так:
Code:
result = {}
arr.each do |sub_arr|
currency, amount = sub_arr[0], sub_arr[1]
result[currency] ||= 0 #мы проверяем есть ли в хэше значение с таким ключем, если нет - инициализируем этот ключ со нулевым значением
result[currency] += amount
end
result #=> { 'EUR' => 300, 'USD' => 200 }
А можно сделать так:
Code:
#result - результат выполнение предыдущего блока
#sub_arr - текущий элемент массива
#в метод inject аргументом передаем то значение, которые передасться как result для самого первого блока, ведь для него не было предыдущего. По умолчанию - nil, в нашем случае - {}
arr.inject({}) do |result, sub_arr|
#в следующий блок в переменную result передасться последнее выражение в этом блоке
currency, amount = sub_arr[0], sub_arr[1]
result[currency] ||= 0
result[currency] += amount
result
end
Простой пример - сумма всех элементов в массиве
Code:
[1, 2, 3, 4, 5].inject(0) { |result, element| result + element }
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
11 года 8 мес. назад #73015
от Amphilohiy
Я верю, что иногда компьютер сбоит, и он выдает неожиданные результаты, но остальные 100% случаев это чья-то криворукость.
Amphilohiy ответил в теме array tricks
Спасибо,
Напомнило мноструозные итераторы ЛУА, в которых еще инвариантные состояния есть... Он по сути и тут есть, но это сам массив
Я верю, что иногда компьютер сбоит, и он выдает неожиданные результаты, но остальные 100% случаев это чья-то криворукость.
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
Время создания страницы: 0.093 секунд
