Итерация по списку - PullRequest
       25

Итерация по списку

1 голос
/ 30 марта 2020

Я очень новичок в Python, поэтому этот вопрос.

У меня есть список, который представляет даты, т.е. понедельники в марте и начале апреля

[2, 9, 16, 23, 30, 6]

Список ' color_sack 'создан на основе нашего сайта местного совета.

Я использую

next_rubbish_day = next(x for x in color_sack if x > todays_date.day)

todays_date.day возвращает только число, представляющее день, т.е. 30

Это имеет работал хорошо весь месяц до сегодняшнего дня 30-го, когда теперь отображается ошибка

next_rubbish_day = next(x for x in color_sack if x > todays_date.day)
StopIteration

Можно ли пройти по списку лучшим способом, чтобы next_rubbish_day заполнял 6 после 30 из списка выше. Я могу понять, почему он не работает, но не может работать лучше.

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

Ответы [ 3 ]

0 голосов
/ 30 марта 2020

Рассмотрим, если ваш текущий месяц - март, а соответствующий список дат - [2, 9, 16, 23, 30, 6], а сегодняшняя дата - 30, в основном мы делаем следующее:

  1. Проверка наличия какой-либо даты в color_sack это больше, чем
    сегодняшняя дата, если это так, мы получаем эту дату. В нашем случае ни одна дата в списке не превышает 30.
  2. Если условие 1st не выполняется, мы теперь выясняем индекс максимальной даты в color_sack, в нашем случае максимальная дата равна 30 и его индекс 4, теперь мы выяснили, есть ли idx больше индекса максимальной даты в списке, если это так, мы возвращаем эту дату.

Этот алгоритм будет соответствовать любым датам в текущем месяце, например, March. Как только начинается новый месяц, например. «Апрель начинается, список будет обновлен с новыми датами с понедельника по апрель до начала мая». Таким образом, этот алгоритм всегда будет соответствовать.

Попробуйте это:

def next_rubbish_day(color_sack, todays_date):
    for idx, day in enumerate(color_sack):
        if day > todays_date or idx > color_sack.index(max(color_sack)):
            yield day

print(next(next_rubbish_day(color_sack, 6)))
print(next(next_rubbish_day(color_sack, 10)))
print(next(next_rubbish_day(color_sack, 21)))
print(next(next_rubbish_day(color_sack, 30)))
print(next(next_rubbish_day(color_sack, 31)))

ВЫХОД:

9
16
23
6
6
0 голосов
/ 30 марта 2020

Спасибо за помощь, я использовал фрагмент MisterMiyagi, так как он сейчас работает.

Вот полный код:

import datetime
import requests
import calendar
from bs4 import BeautifulSoup
from datetime import date


def ord(n):  # returns st, nd, rd and th
    return str(n) + (
        "th" if 4 <= n % 100 <= 20 else {
            1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
    )


# Scrapes rubbish collection dates
URL = "https://apps.castlepoint.gov.uk/cpapps/index.cfm?roadID=2767&fa=wastecalendar.displayDetails"
raw_html = requests.get(URL)
data = BeautifulSoup(raw_html.text, "html.parser")

pink = data.find_all('td', class_='pink', limit=3)
black = data.find_all('td', class_='normal', limit=3)
month = data.find('div', class_='calMonthCurrent')

# converts .text and strip [] to get month name
month = str((month.text).strip('[]'))

todays_date = datetime.date.today()
print()

# creats sack lists
pink_sack = []
for div in pink:
    n = div.text
    pink_sack.append(n)
pink_sack = list(map(int, pink_sack))
print(f"Pink list {pink_sack}")

black_sack = []
for div in black:
    n = div.text
    black_sack.append(n)
black_sack = list(map(int, black_sack))
print(f"Black list {black_sack}")

# creats pink/black list
color_sack = []
color_sack = [None]*(len(pink_sack)+len(black_sack))
color_sack[::2] = pink_sack
color_sack[1::2] = black_sack
print(f"Combined list {color_sack}")
print()
print()

# checks today for rubbish
if todays_date.day in color_sack:
    print(f"Today {(ord(todays_date.day))}", end=" ")
if todays_date.day in pink_sack:
    print("is pink")
elif todays_date.day in black_sack:
    print("is black")

# Looks for the next rubbish day
next_rubbish_day = next(
    (x for x in color_sack[:-1] if x > todays_date.day),
    color_sack[-1],
)

# gets day number
day = calendar.weekday(
    (todays_date.year), (todays_date.month), (next_rubbish_day))


# print(next_rubbish_day)
print(f"Next rubbish day is {(calendar.day_name[day])} the {(ord(next_rubbish_day))}" +
      (" and is Pink" if next_rubbish_day in pink_sack else " and is Black"))
print()

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

0 голосов
/ 30 марта 2020

next принимает необязательное значение по умолчанию , которое возвращается, когда итерация пуста. Если color_sack постоянно имеет день первого числа следующего месяца в последней позиции, верните его по умолчанию:

next_rubbish_day = next(
    (x for x in color_sack[:-1] if x > todays_date.day),
    color_sack[-1],
)

Обратите внимание, что эта схема не сообщит вам, пролонгировали ли вы. Он только скажет вам, что следующая дата - 6-е, а не 6-е апреля против 6-го марта.

Чтобы избежать индексов magi c, рассмотрите возможность разделения вашего списка явным образом и присвоения имен каждой части.

*this_month, fallback_day = color_sack
next_rubbish_day = next(
    (day for day in this_month if day > todays_date.day),
    fallback_day,
)

Если вам необходимо знать месяц, обращайтесь к StopIteration явно:

try:
    day = next(x for x in color_sack[:-1] if x > todays_date.day)
except StopIteration:
    day = color_sack[-1]
    month = 'next'
else:
    month = 'this'
print(f'Next date is {day} of {month} month')
...