J'ai une liste comme ci-dessous:
for word in devices[:]: if word.startswith("nvme0n1","nvme0n1p1","nvme0n1p128"): devices.remove(word)
Je veux supprimer quelques tuples de cette liste contenant nvme1n1
ou nvme0n1p1
ou nvme0n1p128
ou nvme0n1
.
donc la liste finale aura
final_device = [('nvme2n1',),('nvme3n1',)]
essayé comme ci-dessous mais n'a pas fonctionné et a obtenu l'erreur "AttributeError: 'tuple' object has no attribute 'startswith'"
device = [('nvme2n1',), ('nvme1n1', '/local'), ('nvme0n1',), ('nvme0n1p1', '/'), ('nvme0n1p128',), ('nvme3n1',)]
Quelqu'un peut-il aider avec ça?
5 Réponses :
Les word
vous parcourez dans la liste des devices
sont des tuples. Vous devez accéder à la partie de ce tuple qui vous intéresse comme suit:
for word in devices[:]: if word[0] in ["nvme0n1","nvme0n1p1","nvme0n1p128"]: devices.remove(word)
Belle réponse qui résout le problème. Il y a une faute de frappe, cependant, les devices[:]
devraient simplement être des device
. J'ai essayé de proposer une modification, mais les modifications doivent comporter au moins 6 caractères D =
Cela fonctionne comme je l'ai écrit, mais vous avez certainement raison de dire que c'est plus propre de cette façon. Merci @Asker. J'ai fait le changement que vous recommandiez.
@Asker @JamesTollefson le [:]
est en fait nécessaire pour que cela fonctionne, sinon vous modifiez la liste en l'itérant, ce qui fera sauter certains éléments. Essayez-le avec les devices = [(1,), (2,), (3,), (4,)]
et if word[0] in [1, 2, 3]: ...
- la liste résultante est [(2,), (4,)]
, ie (2,)
n'est pas supprimé. Ce comportement est quelque peu décrit ici et ici .
@Czaporka Bon point, je n'ai pas pensé à ça! Désolé JamesTollefson pour la suggestion de modification erronée
Intéressant, @Czaporka, je n'en savais rien.
[('nvme2n1',), ('nvme1n1', '/local'), ('nvme3n1',)]
Vous pouvez même utiliser une compréhension de liste pour le rendre plus simple. Comme James l'a mentionné dans sa réponse, vous devez faire le word[0]
car le word
est un tuple et non une chaîne.
startswith
peut prendre un tuple pour vérifier.
[dev for dev in devices if dev[0] not in ("nvme0n1","nvme0n1p1","nvme0n1p128")]
Mais si vous recherchez des correspondances exactes, vous pouvez le faire,
[dev for dev in devices if not dev[0].startswith(("nvme0n1","nvme0n1p1","nvme0n1p128"))]
La réponse de @ JamesTollefson est agréable et va au cœur du problème.
En remarque, je voulais juste ajouter que lorsque vous traitez avec des listes et des dictionnaires, vous pouvez rendre votre code plus concis et élégant en utilisant des compréhensions de liste:
devices = [d in devices if d[0] not in {"nvme0n1", "nvme0n1p1", "nvme0n1p128", "nvme0n1"}]
La question est un peu vague de savoir exactement quels critères doivent être mesurés.
Par exemple, doit-il être une correspondance exacte, contenir ou commencer par.
Vous trouverez ci-dessous une solution complète que j'ai élaborée pour proposer quatre cas et solutions.
Il y a aussi l'élément supplémentaire de faire correspondre quoi que ce soit dans un tuple si l'index est inconnu.
Si vous rencontrez des problèmes avec le code / avez des suggestions, je serai ravi de le modifier.
Il y a aussi une épreuve future, donc utiliser la liste des éléments à supprimer en ligne et ne pas la définir sur une variable doit être évitée. Cette solution est donc plus générale.
Utilisation de ce qui suit avec: final_device = remove_from_tuple_list (device, remove_list, 0, match_type = 'contains')
Résout le problème spécifique du PO.
Le code est entièrement commenté avec des explications.
device = [('nvme2n1',), ('nvme1n1', '/local'), ('nvme0n1',), ('nvme0n1p1', '/'), ('nvme0n1p128',), ('nvme3n1',)] remove_list = ['nvme1n1', 'nvme0n1p1' , 'nvme0n1p128', 'nvme0n1'] def analyze_item_criteria(item : str ,criteria : list,criteria_type : str): ''' Check whether an item string or tuple is contained in a list of items Args: item : the item to be evaluated criteria : list of items to be checked against criteria_type: the type of criteria Returns: Boolean True/False if evaluated None if not evaluated Raises: 'Invalid criteria_type specified' : if the item is not a valid criteria type ''' ##Check that type is valid assert criteria_type in ['contains', 'exact', 'starts_with', 'ends_with', ],'Invalid criteria_type specified' if criteria_type == 'exact': if item in criteria: return True else: return False ##Starts with/ends with also takes a tupe (.startswith((args,))) this implementation ##Isn't really different from what happens under the hood elif criteria_type == 'starts_with': if any([item.startswith(x) for x in criteria] ): return True else: return False elif criteria_type == 'ends_with': if any([item.endswith(x) for x in criteria] ): return True else: return False elif criteria_type == 'contains': if any([x in item for x in criteria]): return True else: return False #Specifying no index does not really work with well exact but the other three options are still valid def remove_from_tuple_list(tuple_list : list, remove_list :list, tuple_index : int = None, match_type : str = 'contains'): ''' Function to remove items from a list of tuples containing specific words. The function can remove items at a specified index or any position if not specified Args: tuple_list : The list of tuples from which items are to be removed (items in tuple have to be str/int/float , objects will have unexpected behaviour) remove_list : list of strings/items to be removed from the tuple_list tuple_index : if an integer, checks for criteria at the specific position otherwise the whole tuple which is inefficient Set to none if you want to analyze a list of strings for example as well match_type : Do we want to match the word exactly or do we look for it containing the word There are a few cases to consider here. - contains - exact - starts_with - ends_with Returns: list of items not in remove_list Raises: 'Invalid match_type specified' : if the item is not in the match list ''' ##Check that type is valid assert match_type in ['contains', 'exact', 'starts_with', 'ends_with', ],'Invalid match_type specified' new_tuple_list = [] #Check whether we are looking at a specific index in the tuple ##This can be done multiple ways, think analysing the if once is the most efficient so justifies the additional typing if isinstance(tuple_index,int): new_tuple_list = [ list_item for list_item in tuple_list if not analyze_item_criteria(list_item[tuple_index],remove_list,match_type) ] else: new_tuple_list = [list_item for list_item in tuple_list if not analyze_item_criteria('|'.join([str(x) for x in list_item]) ,remove_list,match_type)] return new_tuple_list def test(): final_device = remove_from_tuple_list(device,remove_list,0,match_type = 'contains') print(remove_from_tuple_list(device,remove_list,0,match_type = 'contains')) print(remove_from_tuple_list(device,remove_list,0,match_type = 'exact')) remove_list = ['nvme1n1', 'nvme0n1p1', 'nvme0n1'] print(remove_from_tuple_list(device,remove_list,0,match_type = 'ends_with')) print(remove_from_tuple_list(device,remove_list,0,match_type = 'starts_with')) print(remove_from_tuple_list(device,remove_list,None,match_type = 'contains')) print(remove_from_tuple_list(device,remove_list,None,match_type = 'exact')) remove_list = ['nvme1n1', 'nvme0n1p1', 'nvme0n1'] print(remove_from_tuple_list(device,remove_list,None,match_type = 'ends_with')) print(remove_from_tuple_list(device,remove_list,None,match_type = 'starts_with')) ''' Output: ------- [('nvme2n1',), ('nvme3n1',)] [('nvme2n1',), ('nvme3n1',)] [('nvme2n1',), ('nvme0n1p128',), ('nvme3n1',)] [('nvme2n1',), ('nvme3n1',)] [('nvme2n1',), ('nvme3n1',)] [('nvme2n1',), ('nvme1n1', '/local'), ('nvme0n1p1', '/'), ('nvme0n1p128',), ('nvme3n1',)] [('nvme2n1',), ('nvme1n1', '/local'), ('nvme0n1p1', '/'), ('nvme0n1p128',), ('nvme3n1',)] [('nvme2n1',), ('nvme3n1',)] '''
if word[0] == "nvme0n1" or word[0] == "nvme0n1p1" or word[0] == "nvme0n1p128"