1
votes

Itération à travers une liste

Je suis très nouveau dans Python d'où cette question.

J'ai une liste qui représente les dates c'est-à-dire les lundis de mars et début avril

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

La liste, 'color_sack' est créé à partir d'un extrait du site Web de notre conseil local.

J'utilise

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

todays_date.day renvoie uniquement le nombre représentant le jour, soit 30

Cela a bien fonctionné tout le mois jusqu'à aujourd'hui 30, quand il affiche maintenant une erreur

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

Est-il possible de parcourir la liste d'une meilleure façon afin que next_rubbish_day remplirait le 6 après le 30 de la liste ci-dessus. Je peux voir pourquoi cela ne fonctionne pas, mais je ne peux pas trouver une meilleure solution.

Lorsque le mois d'avril commencera, la liste sera mise à jour avec les nouvelles dates pour les lundis d'avril à début mai


2 commentaires

Une approche serait next (itertools.drop while (lambda x: x <= todays_date.day, color_sack)) , mais cela se déclenchera, disons, le 31 lorsque tout les dates suivantes sont inférieures au jour en cours. Vous devrez parcourir cette liste avec une connaissance réelle du moment où les jours se dérouleront dans le mois suivant.


Utilisez next ((x for x in color_sack if x> todays_date.day), color_sack [-1]) pour obtenir le 6 avril lorsque vous êtes à la fin du mois de mars. Notez que cela ne vous dira pas réellement que votre résultat est le mois prochain (il indique simplement 6, pas 6 avril ou 6 mars). Travailler avec des dates réelles au lieu d'un simple jour du mois serait plus robuste.


3 Réponses :


0
votes

3 commentaires

Je pense que supposer que le dernier indice est la valeur par défaut est naïf; peut-être que cela fonctionnera la plupart du temps, jusqu'à ce que ce ne soit pas le cas…


@deceze Le PO dit "J'ai une liste qui représente les dates, c'est-à-dire les lundis de mars et début avril " et "Lorsque le mois d'avril commencera, la liste sera mise à jour avec les nouvelles dates pour les lundis d'avril jusqu'à début mai ". Ainsi, le "jour de repli" sera toujours là et toujours après les jours du mois en cours. Même si nous considérons des données erronées telles que "contient un ou plusieurs jours du mois suivant", il est facile de les nettoyer pour obtenir les données requises.


Que fait le * au début de cette ligne: * this_month, fallback_day = color_sack. Pas vu ça avant.



0
votes

Tenez compte du fait que si votre mois actuel est mars et que la liste des dates correspondante est [2, 9, 16, 23, 30, 6] et que la date du jour est 30 , en gros, ce que nous faisons est:

  1. Vérifier si une date dans color_sack est supérieure à
    la date d'aujourd'hui, si c'est le cas, nous la cédons. Dans notre cas, aucune date de la liste n'est supérieure à 30 .
  2. Si la condition 1st échoue, nous trouvons maintenant l'index de la date maximum dans le color_sack , dans notre cas la date maximum est 30 et son index est 4 , maintenant nous avons découvert s'il y a un idx plus grand que l'index de date maximum dans la liste, si c'est alors nous retournons cette date.

Cet algorithme sera conforme à toutes les dates du mois en cours, par exemple Mars . Dès que le nouveau mois commence par exemple. "Début avril, la liste sera mise à jour avec les nouvelles dates pour les lundis d'avril à début mai". Donc, cet algorithme sera toujours conforme.

Essayez ceci:

9
16
23
6
6

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)))

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


0 commentaires

0
votes

Merci pour l'aide, j'ai utilisé l'extrait de MisterMiyagi car cela semble fonctionner pour le moment.

Voici le code complet:

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()

Il y en a probablement tellement des moyens plus efficaces de le faire, je suis donc ouvert aux suggestions et j'apprends toujours.


1 commentaires

Je viens de me rendre compte que cela n'a pas fonctionné car le 6 arrive comme vendredi parce que le programme pense que c'est mars au lieu d'avril. Je vais jeter un oeil à d'autres options ici