Пошаговое руководство по вопросам кодирования.
Как и большинство молодых разработчиков, я ищу работу, и поиск работы включает в себя множество проблем с кодом. Теперь, технически, после того, как я высмеял последний вызов кода, который я сделал, это действительно всплыло на собеседовании для компании FAANG. Так что я могу сглазить себя.
Но этот вызов кода был довольно практическим примером. Кроме того, меня специально попросили использовать Ruby, так как это будет стек компании. Чтобы не судиться со мной, некоторые переменные изменены.
Given an array of people we have to pay with an amount of money that would be sent to a popular payment API like Stripe or Braintree, organize each payment into a separate group so that each transaction can be grouped with another transaction from a different person, but not two of the same. Also take in as an optional argument a maximum group size for a group of payments in case we need that with a default size of 100.
Это казалось достаточно простым, но оказалось немного сложнее, чем я представлял. Для начала у нас есть что-то вроде этого:
module PayPeople end
И мы знаем, что нам понадобится что-то, что платит людям внутри этого модуля и принимает массив и необязательный max_group_size
.
Итак, теперь у нас есть что-то вроде:
module PayPeople def self.group_payments(pay_array, max_group_size=100) end end
Прогресс! Но мы до сих пор ничего не сделали с нашими аргументами.
Кроме того: мы используем ключевое слово self, поскольку это модуль Ruby, набор методов, которые мы можем вызывать и которые принадлежат одному файлу, но которые мы можем вызывать в нашем приложении с некоторым синтаксисом импорта.
Что ж, мне нравится сначала думать о том, что я собираюсь вернуть в конце моей функции, когда обдумываю проблему, которая будет массивом массивов, поскольку мы разбиваем список платежей на разные группы. Я знаю, что там будет по крайней мере одна группа, если мы будем иметь дело с некоторыми платежами. Итак, я назначу свою возвращаемую переменную вот так.
module PayPeople def self.group_payments(pay_array, max_group_size=100) final = [[]] # an array of arrays #do stuff here final # the last line of a Ruby method is what is returned. end end
Хорошо, больше прогресса! Теперь у нас есть структура того, что наша функция принимает и возвращает. А теперь давайте подумаем, что мы делаем. Что ж, я знаю, что мне понадобится цикл по массиву объектов или хэшей для проверки каждого из них, поэтому есть способ сделать это в Ruby с синтаксисом .each.
module PayPeople def self.group_payments(pay_array, max_group_size=100) final = [[]] # an array of arrays pay_array.each do |payment| # do something with the payment here end final # the last line of a Ruby method is what is returned. end end
Хорошо, теперь у нас есть доступ к каждому платежу. Но нам нужно увидеть, есть ли пользователь / адрес электронной почты уже в массиве платежей, поэтому нам понадобится второй цикл здесь! В этом нам нужно будет проверить каждый массив в нашем последнем массиве, чтобы увидеть, есть ли в нем пользователь. На этот раз я собираюсь использовать цикл for / in:
module PayPeople def self.group_payments(pay_array, max_group_size=100) final = [[]] # an array of arrays pay_array.each do |payment| for arr in final do # for each array in our final array do something end end final # the last line of a Ruby method is what is returned. end end
Хорошо, теперь мы очень близки, и наш код становится беспорядочным. Нам понадобится оператор if / else, чтобы увидеть, находится ли платеж уже в одной из наших групп массивов в нашем последнем массиве, но вместо того, чтобы писать туда большую часть логики, я решил написать второй вспомогательный метод, чтобы упростить эту задачу. Я рекомендую эту технику, если ваш код становится беспорядочным в напряженной ситуации.
module PayPeople def self.group_payments(pay_array, max_group_size=100) final = [[]] # an array of arrays pay_array.each do |payment| for arr in final do # for each array in our final array do something end end final # the last line of a Ruby method is what is returned. end # new stuff def self.isEmailThere?(array, email) # let's check for an email! end end
Отлично, теперь у нас есть второй метод, который мы собираемся использовать, и здесь я собираюсь использовать необычный синтаксис и метод include?. Обратите внимание, что у моей вспомогательной функции есть знак «?» в нем, потому что по соглашению в Ruby функции, возвращающие логическое, как у нас, обычно заканчиваются знаком «?»
def self.isEmailThere?(array, email) array.map{|payment| payment[:email]}.include?(email) end
Таким образом, это говорит о том, что для каждого массива, для каждого платежа в этом массиве мы проверяем, включает ли электронное письмо адрес электронной почты, который мы передаем. Мы делаем это, изменяя наш массив платежей на массив электронных писем, а затем проверяя, является ли наш адрес электронной почты из их.
Мы почти закончили!
Теперь единственное, что мы должны принять во внимание, - это максимальный размер группы и то, что нам нужно сделать, а именно push в какой массив зависит. Окончательный код будет выглядеть так!
module PayPeople def self.group_payments(pay_array, max_group_size=100) final = [[]] # an array of arrays pay_array.each do |payment| for arr in final do if !PayPeople.isEmailThere?(arr, payment[:email]) && arr.length < max_group_size arr.push(payout) break else final.push([payment]) break end end end final end def self.isEmailThere?(array, email) array.map{|payment| payment[:email]}.include?(email) end end
Это много «if» и «end», но в основном это говорит о том, что если массив в final
не включает текущий адрес электронной почты и он достаточно мал, то давайте вставим туда информацию о платеже, в противном случае вставим ее в новый массив !
Пример ввода может выглядеть так:
example = [ { email: "[email protected]", amount: 400 }, { email: "[email protected]", amount: 8000 }, { email: "[email protected]", amount: 400 }, { email: "[email protected]", amount: 300 }, { email: "[email protected]", amount: 12 }, { email: "[email protected]", amount: 675 } ]
И пример вывода может выглядеть так:
[[{:email=>"[email protected]", :amount=>400}, {:email=>"[email protected]", :amount=>8000}, {:email=>"[email protected]", :amount=>300}, {:email=>"[email protected]", :amount=>675}], [{:email=>"[email protected]", :amount=>400}], [{:email=>"[email protected]", :amount=>12}]]
Поскольку у нас есть два «Боба» и два «Алана», они помещаются в два разных массива. Успех!
Это не очень элегантное решение с точки зрения времени. Я немного улучшил его, добавив операторы break, чтобы после завершения вставки мы перестали зацикливаться для каждого платежа, но это все еще Big O экспоненциального времени, что означает, что это не быстрое решение этой проблемы, так как оно будет становиться все более сложным по мере увеличения размера ввода.
Если у кого-то есть более быстрое / крутое решение, пожалуйста, троллите меня в комментариях;)
Говоря о быстром и крутом, я думаю, что Рейнджер, которого я встретил в Проспект-парке, и то и другое.
Конечно, на этой фотографии вы бы не стали этого делать, но рейнджер - настоящий смотритель парка, поэтому он знает, когда сесть и подождать.
У него есть скорость и дисциплина, чтобы решать сложные задачи по программированию или, по крайней мере, тискать мое сердце.
Бай пока!
ник