Задача Google Python № 2.а

Обслуживание лифта

Это продолжение моего опыта работы с онлайн-программированием Google, вы знаете, что внезапно появляется, когда вы гуглите что-то о питоне, и разрушает вашу идеально спланированную неделю 🙂

Если вам нужно представление, пожалуйста, проверьте мою исходную публикацию, в которой я отвечу на первый вопрос:



Задача Google Python №1
Пирог - не ложь. medium.com



⚠️ Spoilers/Warnings: If you get an invitation and decide to accept it I encourage you to try your best to solve the challenges by yourself, least you ruin your opportunity for an interview. 
If you are going to copy paste this or another answer from Stack Overflow I have no say in the matter and I think this is another place where coding interviews get it wrong, there are only so many ways to solve a problem and coding is more and more a mix of communal group think and personal creativity but I digress. At the very least I hope you seek to understand the technical problem and be able to explain it in your voice, which is what I think these tests want.
For the rest of us, this is just a coding riddle which either you love, hate or are trying to get better at.

После завершения последнего испытания и запроса нового вы получите зловещее сообщение вместе с новой папкой / задачей:

Вот:

Elevator Maintenance
====================

You've been assigned the onerous task of elevator maintenance - ugh! It wouldn't be so bad, except that all the elevator documentation has been lying in a disorganized pile at the bottom of a filing cabinet for years, and you don't even know what elevator version numbers you'll be working on. 

Elevator versions are represented by a series of numbers, divided up into major, minor and revision integers. New versions of an elevator increase the major number, e.g. 1, 2, 3, and so on. When new features are added to an elevator without being a complete new version, a second number named "minor" can be used to represent those new additions, e.g. 1.0, 1.1, 1.2, etc. Small fixes or maintenance work can be represented by a third number named "revision", e.g. 1.1.1, 1.1.2, 1.2.0, and so on. The number zero can be used as a major for pre-release versions of elevators, e.g. 0.1, 0.5, 0.9.2, etc (Commander Lambda is careful to always beta test her new technology, with her loyal henchmen as subjects!).

Given a list of elevator versions represented as strings, write a function answer(l) that returns the same list sorted in ascending order by major, minor, and revision number so that you can identify the current elevator version. The versions in list l will always contain major numbers, but minor and revision numbers are optional. If the version contains a revision number, then it will also have a minor number.

For example, given the list l as ["1.1.2", "1.0", "1.3.3", "1.0.12", "1.0.2"], the function answer(l) would return the list ["1.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]. If two or more versions are equivalent but one version contains more numbers than the others, then these versions must be sorted ascending based on how many numbers they have, e.g ["1", "1.0", "1.0.0"]. The number of elements in the list l will be at least 1 and will not exceed 100.
Test cases
==========

Inputs:
    (string list) l = ["1.1.2", "1.0", "1.3.3", "1.0.12", "1.0.2"]
Output:
    (string list) ["1.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]

Inputs:
    (string list) l = ["1.11", "2.0.0", "1.2", "2", "0.1", "1.2.1", "1.1.1", "2.0"]
Output:
    (string list) ["0.1", "1.1.1", "1.2", "1.2.1", "1.11", "2", "2.0", "2.0.0"]

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

# Throw pythons sorted function and see what happens..
versions = ["2.0","1.0","5.0","3.0"]
def solution(l):
    return sorted(l)
print(solution(versions))
# >>  ['1.0', '2.0', '3.0', '5.0']

К сожалению, если мы добавим два тестовых примера нашему решению, мы не получим ожидаемого ответа:

Exp =  Expected
# versions = ["1.1.2", "1.0", "1.3.3", "1.0.12", "1.0.2"]
Got: ['1.0', '1.0.12', '1.0.2', '1.1.2', '1.3.3’]
Exp: ["1.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]
# versions = ["1.11", "2.0.0", "1.2", "2", "0.1", "1.2.1", "1.1.1", "2.0"]
Got: ['0.1', '1.1.1', '1.11', '1.2', '1.2.1', '2', '2.0', '2.0.0’]
Exp: ["0.1", "1.1.1", "1.2", "1.2.1", "1.11", "2", "2.0", "2.0.0"]

Эту проблему обманчиво легко понять для нас, людей, но нам нужно немного подумать, чтобы объяснить ее компьютеру. В первом случае 1.0.12 сортируется до 1.0.2, потому что sorted помещает его первым , вероятно, потому, что он не анализирует версию по точкам и обрабатывает ее как строку, поэтому стратегия, которой следует придерживаться сейчас становится несколько понятным, проанализируйте каждую строку как число, затем отсортируйте, давайте проанализируем ...

⚠️ NOTE: Somewhere buried in the requirements which I didn't print and vaguely remember, there is the mention that your code will be tested using a very specific version of python: Python 2.7.13, some of the following coding snippets won't run on a different version, but you can substitute list comprehension for regular loops, so;
parsed = [e.split(".") for e in l]
can be rewritten as:
parsed = []
for e in l:
    parsed.append(e.split("."))

See also: Python Comprehension
And if you need to setup a different python environment like I did I recommend conda
# Parse by dot with split:
versions = ["1.0.12", "1.0.2"]
def solution(l):
    parsed = [e.split(".") for e in l] 
    return parsed
print(solution(versions))
# >>  [['1', '0', '12'], ['1', '0', '2']]

Теперь нам нужно преобразовать строки в числа int:

# Cast parsed list elements in to ints:
def solution(l):
    parsed = [e.split(".") for e in l]
    toSort = [map(int, e) for e in parsed]
for i,version in enumerate(toSort):
        print(list(toSort[i]))
solution(versions)
# >> 
[1, 0, 12]
[1, 0, 2]

Завершив предварительную обработку, давайте посмотрим, исправлена ​​ли проблема с сортировкой:

def solution(l):
    parsed = [e.split(".") for e in l]
    toSort = [map(int, e) for e in parsed]
    sortedINTs = sorted(toSort)
    return sortedINTs
print(solution(versions))
# >> [[1, 0, 2], [1, 0, 12]]

Выглядит неплохо, все, что нам нужно сделать сейчас, это заново интегрировать каждый элемент списка в формат управления версиями (отдельные точки) после сортировки ...

def solution(l):
    parsed = [e.split(".") for e in l]
    toSort = [map(int, e) for e in parsed]
    sortedINTs = sorted(toSort)
    sortedJoined = [('.'.join(str(ee) for ee in e)) for e in sortedINTs]
    return sortedJoined
# >> ['1.0.2', '1.0.12']

Осталось только провести кучу тестовых примеров и посмотреть, как все пойдет ...

versions = ["1.1.2", "1.0", "1.3.3", "1.0.12", "1.0.2"]
Got: ['1.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3’]
Exp: ["1.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]

versions = ["1.11", "2.0.0", "1.2", "2", "0.1", "1.2.1", "1.1.1", "2.0"]
Got: ['0.1', '1.1.1', '1.2', '1.2.1', '1.11', '2', '2.0', '2.0.0']
Exp: ["0.1", "1.1.1", "1.2", "1.2.1", "1.11", "2", "2.0", "2.0.0"]
Couple of extra tests with edge cases:
versions = ["1.1.1","1.1.11","1.1.9"]
Exp ?: ['1.1.1', '1.1.9', '1.1.11']
Got:   ['1.1.1', '1.1.9', '1.1.11']
versions = ["1.1.1","1.0.8","1.0.9", "1.0.0", "1", "2"]
Exp ?: ['1', '1.0.0', '1.0.8', '1.0.9', '1.1.1', '2']
Got:   ['1', '1.0.0', '1.0.8', '1.0.9', '1.1.1', '2']

И отправляем его, чтобы продвинуться дальше…

Управление версиями в реальном мире

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

from distutils.version import StrictVersion,LooseVersion
versions = ["1.11", "2.0.0", "1.2", "2", "0.1", "1.2.1", "1.1.1", "2.0"]
sortedVersions = sorted(versions, key=LooseVersion)
print(sortedVersions)
# Got: ['0.1', '1.1.1', '1.2', '1.2.1', '1.11', '2', '2.0', '2.0.0']
# Exp: ["0.1", "1.1.1", "1.2", "1.2.1", "1.11", "2", "2.0", "2.0.0"]
No idea if this passes tests, but you can use it for your real world versioning needs 🙂
Note: Under StricVersion this fails because of the 2 version number which is not allowed see more here:
http://epydoc.sourceforge.net/stdlib/distutils.version.StrictVersion-class.html


Выводы и признания.

Я собираюсь выровняться с вами, вскоре после того, как погуглил, как работает управление версиями в python, я наткнулся на вопрос StackOverflow, где была дана немного другая версия вышеупомянутого решения (более подробная с циклами for), не подразумевалось никакого упоминания о проблеме Google foobar, но списки версий были те же, я думаю ..

Проблема в том, что как только вы прочитаете чей-то ответ или даже пробежитесь по решению, вы подсознательно сделаете его своим, что идеально подходит для вашей повседневной работы и разгадывания загадок, но я понятия не имею, как Google видит это, я Знаю, что некоторые сайты Leetcode требуют оригинальных ответов, что еще раз заставляет меня сомневаться в технических вопросах, проблемах и leetcode как правильном способе оценки программистов, в конце концов, существует не так много способов ответить на каждый вопрос ... см. также:



Независимо от аспектов найма, эта задача была довольно разнообразной и почти простой, но снова мне помогли SO и питоны sorted, map и split (наряду с пониманием списка). Этот вызов можно использовать как грубый учебник / пример, и я надеюсь, вы найдете для него какое-то применение.

Спасибо за чтение !