def this_and_prev(iterable):
    iterator = iter(iterable)
    prev_item = None
    curr_item = next(iterator)
    for next_item in iterator:
        yield (prev_item, curr_item)
        prev_item = curr_item
        curr_item = next_item
    yield (prev_item, curr_item)

for i,j in this_and_prev( range(5) ): 
    print(i,j)

"""
Explanation: <h2>Problem 1. Python / Generator functions</h2>

Следующая функция возвращает текущее и предыдущее значения в цикле:
End of explanation
"""


def this_and_next(iterable): # немного изменил код по сравнению с предыдущей функцией, если следующего значения нет, возвращаем ноль
    iterator = iter(iterable)
    curr_item = next(iterator)
    for next_item in iterator:
        yield (curr_item, next_item)
        curr_item = next_item
    yield (curr_item, None)
    
for i,j in this_and_next( range(5) ): 
    print(i,j)

"""
Explanation: По аналогии требуется написать функцию, которая будет возвращать текущее и следующее значения.
<i>Type your code below</i>
End of explanation
"""


def row_number(driver_id, input_data):
    sorted_data = sorted(input_data, lambda x: x[0]) # сортируем список входных данных по дате
    result = []
    row_number = 0
    while row_number <= range( 0, len(input_data) ):
        row_data = {'row_number': row_number
                    , 'driver_id': driver_id
                    , 'start_timestamp': sorted_data[row_number][0]
                    , 'status': sorted_data[row_number][1]
                    }
        row_number += 1
        result.append(row_data)
    return result

$row_number = Python::row_number(driver_id, input_data);

$raw = (
    SELECT 
            driver_id
            , start_timestamp
            , status
    FROM    sample_table
    );

$reduced = (
    REDUCE $raw
       ON  driver_id
    USING  $row_number((start_timestamp, status))
    );

SELECT * FROM $reduced;

"""
Explanation: <h2>Problem 2. SQL / Python</h2>

Есть следующая SQL таблица <b>sample_table</b>:
<table>
<tr><td>column name</td><td><b>driver_id</b></td> <td><b>start_timestamp</b></td> <td><b>status</b></td></tr>
<tr><td>data type</td><td><i>(String)</i></td><td><i>(String)</i></td><td><i>(String)</i></td></tr>
<tr><td>1</td><td>driver_id_1</td><td>2017-01-21 00:05</td><td>driving</td></tr>
<tr><td>2</td><td>driver_id_1</td><td>2017-01-21 00:09</td><td>waiting</td></tr>
<tr><td>...</td><td>...</td><td>...</td><td>...</td></tr>
<tr><td>k x n</td><td>driver_id_n</td><td>2017-01-21 23:49</td><td>transporting</td></tr>
</table>


driver_id_i -- идентификатор i-го водителя
start_timestamp -- время начала статуса, в котором находился водитель
status -- статус, в котором находился водитель

Для простоты предположим, что по каждому водителю в таблице одинаковое число записей k.
<hr>
Табличка хранится в СУБД, которая умеет применять к данным функции, написанные на Python. Например, следующий код выполняет функцию ROW_NUMBER():
End of explanation
"""


def LEAD(driver_id, input_data):
    sorted_data = sorted(input_data, lambda x: x[0]) # сортируем список входных данных по дате
    result = []
    row_number = 0
    while row_number < len(input_data) - 1: # для всех состояний конкретного водителя, кроме финального, добавляем ещё одно значеник
        row_data = {'row_number': row_number
                    , 'driver_id': driver_id
                    , 'start_timestamp': sorted_data[row_number][0]
                    , 'status': sorted_data[row_number][1]
                    , 'status_next': sorted_data[row_number + 1][1]
                    }
        row_number += 1
        result.append(row_data)
    row_data = {'row_number': row_number
                , 'driver_id': driver_id
                , 'start_timestamp': sorted_data[row_number][0]
                , 'status': sorted_data[row_number][1]
                , 'status_next': None # если состояние водителя финальное, то ставим в следующий статус значение None
                }
    result.append(row_data)
    return result

"""
Explanation: <hr>
Результат выполненного запроса будет выглядеть как:
<table>
<tr><td>column name</td><td><b>row_number</b></td><td><b>driver_id</b></td> <td><b>start_timestamp</b></td> <td><b>status</b></td></tr>
<tr><td>data type</td><td><i>(Int32)</i></td><td><i>(String)</i></td><td><i>(String)</i></td><td><i>(String)</i></td></tr>
<tr><td>1</td><td>1</td><td>driver_id_1</td><td>2017-01-21 00:05</td><td>driving</td></tr>
<tr><td>2</td><td>2</td><td>driver_id_1</td><td>2017-01-21 00:09</td><td>waiting</td></tr>
<tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr>
<tr><td>k x n</td><td>k</td><td>driver_id_n</td><td>2017-01-21 23:49</td><td>transporting</td></tr>
</table>

<hr>
<b>Вопрос</b>: как нужно переписать код, чтобы реализовать функцию LEAD(), т.е. добавить запись следующего статуса водителя в соседней колонке? Для выполнения задания требуется переписать код.
<i>Type your code below</i>
End of explanation
"""


$orders_card = ( # здесь я предполагал, что исходная таблица имеет название sample_table, вытянули оттуда количество всех заказов, оплаченные картой
    SELECT COUNT(*) 
        FROM sample_table
            WHERE payment_type = 'card'
    );

$orders_cash = ( # количество всех заказов, оплаченных наличными
    SELECT COUNT(*) 
        FROM sample_table
            WHERE payment_type = 'cash'
    );

$orders_card_completed = ( # количество всех выполненных заказов, оплаченных картой
    SELECT COUNT(*) 
        FROM sample_table
            WHERE payment_type = 'card'
                AND status = 'completed'
    );

$orders_cash_completed = ( # количество всех выполненных заказов, оплаченных наличными
    SELECT COUNT(*) 
        FROM sample_table
            WHERE payment_type = 'cash'
                AND status = 'completed'
    );

print(orders_card_completed/orders_card, orders_cash_completed/orders_cash) # посчитали отношения, теперь их нужно сравнить

"""
Explanation: Кроме того, обращаю Ваше внимание на то, что в куске кода "reduce... on... using", возможно, есть ошибка - в аргументах функции row_number, скорее всего, пропущен аргумент driver_id, то есть, по моему мнению, правильным вариантом было бы row_naumber(driver_id, (start_timestamp, status))
<h2>Problem 4. SQL</h2>

Есть следующая таблица с заказами клиентов: 
<table>
<tr><td>column name</td><td><b>id</b></td> <td><b>client_id</b></td> <td><b>driver_id</b></td> <td><b>timestamp</b></td> <td><b>cost</b></td> <td><b>payment_type</b></td> <td><b>status</b></td></tr>
<tr><td>data type</td><td><i>(String)</i></td> <td><i>(String)</i></td> <td><i>(String)</i></td> <td><i>(String)</i></td> <td><i>(Double)</i></td> <td><i>(String)</i></td> <td><i>(String)</i></td> </tr>
<tr><td>1</td><td>some_id</td> <td>some_client_id</td> <td>some_driver_id</td> <td>2016-01-21 12:03</td> <td>123.0</td> <td>cash</td> <td>completed</td> </tr>
<tr><td>2</td><td>some_id</td> <td>some_client_id</td> <td>some_driver_id</td> <td>2016-01-21 11:42</td> <td>99.0</td> <td>card</td> <td>rider_canceled</td> </tr>
<tr><td>...</td><td>...</td> <td>...</td> <td>...</td> <td>...</td> <td>...</td> <td>...</td> <td>...</td> </tr>
<tr><td>n</td><td>some_id</td> <td>some_client_id</td> <td>some_driver_id</td> <td>2016-01-21 15:16</td> <td>0.0</td> <td>card</td> <td>driver_canceled</td> </tr>
</table>

Нужно посчитать следующие метрики:
    1. Как процент выполнения заказов зависит от типа оплаты?
    2. Какой процент активных водителей совершает в неделю более 30 поездок?
    3. Какой процент клиентов, совершивших первую поездку за наличные впоследствии переходит на оплату картой?
<i>Type your answer below</i>
End of explanation
"""


SELECT # перевели все данные в формат datetime
    CONVERT(DATETIME, CONVERT(VARCHAR(30), timestamp), 120)
FROM sample_table;

$sample_table_completed = ( # взяли из таблицы только выполненные заказы
    SELECT *
        FROM sample_table
            WHERE status = 'completed'
    );

$rides_on_a_week = ( # сгруппировали табличку по водителям
        SELECT driver_id, MIN(timestamp) AS first_trip, MAX(timestamp) AS last_trip, COUNT(id) AS count_trips
            FROM sample_table_completed
        GROUP BY driver_id
    );

SELECT driver_id, count_trips / DATEDIFF(week, first_trip, last_trip) #для каждого водителя посчитали среднее его поездок в неделю
    FROM rides_on_a_week

"""
Explanation: Здесь я предполагал, что все водители активные, и считал общее количество поездок, затем делил на количество недель между их первой и последней поездкой в этой базе данных (возможно, стоит аккуратнее считать разницу дат между первой и последней поездкой)
End of explanation
"""


$first_last_trips = ( # для каждого клиента находим дату и время его первой и последней поездки
    SELECT client_id, MIN(timestamp) AS first_trip, MAX(timestamp) AS last_trip
        FROM sample_table_completed
    GROUP BY client_id
);

$joined_table = ( # соединяем таблицы
    SELECT *
        FROM sample_table_completed
    LEFT JOIN first_last_trips
    ON sample_table_completed.client_id = first_last_trips.client_id
);

$clients_paid_first_cash = ( # ищем всех клиентов, которые первую поездку оплатили наличными
    SELECT client_id
        FROM joined_table
    WHERE timestamp = first_trip AND status = 'cash'
);

$clients_paid_first_cash_then_card = ( # ищем всех клиентов, которые первую поездку оплатили картой, а последнюю - наличными
    SELECT client_id
        FROM joined_table
    WHERE timestamp = last_trip AND status = 'card' AND (client_id IN clients_paid_first_cash)
);

$share_of_clients = ( # считаем долю
    SELECT (COUNT(*) 
            FROM clients_paid_first_cash_then_card) / (COUNT(*) FROM clients_paid_first_cash)
);

"""
Explanation: Я предполагаю, что клиент перешёл на оплату картой, если он первую поездку оплатил наличными, а свою последнюю поездку картой. Все таблицы из предыдущих запросов предполагаются сохранёнными.
End of explanation
"""


