【问题标题】:How can I prevent users from entering the same input twice when writing directly to .csv in python在python中直接写入.csv时,如何防止用户输入相同的输入两次
【发布时间】:2020-03-12 05:02:17
【问题描述】:

我正在尝试根据用户输入创建数据集。我试图防止其中一个字段重复。我要求用户选择一个与他们的姓名、年龄、gpa 和专业相匹配的字母。我想确保输入的字母是唯一的,但我不确定在直接写入 .csv 文件时如何执行此操作。

这是我目前所拥有的。

import csv
from colorama import Fore, Back, Style


with open('students2.csv', 'w+', newline='') as csvfile:
        columnheaders = ['NAME','AGE','GPA','MAJOR']
        writer = csv.DictWriter(csvfile, fieldnames=columnheaders)

        writer.writeheader()

        for i in range(0,10):
            askname=input('Please select the letter that matches your name from the following:  (A, B, C, D, E, F, G, H, I, J),  ')
            askage=input('Please enter your Age: ')
            askgpa=input('Please enter your GPA: ')
            askmajor=input('Please select your major from the following (CS, CET, CIS, CE) ')
            writer.writerow({'NAME': askname,'AGE': askage,'GPA': askgpa,'MAJOR': askmajor}) 
            print(Back.BLACK +'My name starts with the letter:', askname ,' and I am ', askage, 'years old. I study ', askmajor, 'and my GPA is: ', askgpa)
            print(Style.RESET_ALL)

我知道如何使用列表来做到这一点,

namelist = []

while True:

    #Input name
    while True:
        name = str(input('What is your name? '))
        if name.upper() not in ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'):
            print("Please use (A, B, C, D, E, F, G, H, I, J).")
            continue
        if name in namelist:
            print("This name has already been used.")
            continue
        else:
            namelist.append(name)
            break 

但是是否有可能做到这一点而不必通过列表进行然后将其转换为 .csv?

任何帮助将不胜感激。 提前致谢。

【问题讨论】:

  • 为什么“不必通过列表进行操作,然后将其转换为 .csv”?这似乎是一个非常合理的解决方案。
  • @Chris 想知道它是否可以在一个进程中完成,而不是两个单独的进程。
  • @JPnova87 你说的进程是什么意思?这听起来像是我们可以花上一辈子争论的词。
  • 您要么必须在写入文件时跟踪内存中的输入(两个“进程”),要么读回文件并查看记录的值(两个“进程”,加上一个吨的低效率)。输入→列表→CSV 解决方案至少同样简单且优雅得多。 (请注意,“过程”的含义与您在计算中所说的非常不同。)
  • 您能否显示一行 csv 文件的格式,您是否对 pandas 的答案感兴趣,其中包含您的问题以做您正在寻找的事情?我赞成你的问题,我认为这是一个很好的问题,csv 很难直接处理。

标签: python python-3.x csv export-to-csv


【解决方案1】:

您需要在内存中保留一份列表副本(您可以每次都扫描 CSV,但这会导致大量不必要的磁盘 IO)。

我的建议是将名称缓存在一个集合中,因此您可以在脚本顶部添加nameseen = set() 之类的内容,然后在编写该行之前对其进行检查。比如:

if not (askname in nameseen):
    writer.writerow({'NAME': askname,'AGE': askage,'GPA': askgpa,'MAJOR': askmajor}) 
    nameseen.add(askname)

    print(Back.BLACK +'My name starts with the letter:', askname ,' and I am ', askage, 'years old. I study ', askmajor, 'and my GPA is: ', askgpa)
    print(Style.RESET_ALL)
else:
    print("This name has already been used.")

【讨论】:

    【解决方案2】:

    如果你可以使用 pandas,你可以这样做:

    import pandas as pd
    df = pd.read_csv('kd.csv', index_col=0)
    df.to_csv()
    # 'NAME,AGE,GPA,MAJOR\nBill,18,4.0,CS\nMike,20,2.9,BS\nWill,20,2.4,CS\nBill,18,4.0,CS\n'
    
    df.drop_duplicates(subset=None, inplace=True)
    df.to_csv()
    # 'NAME,AGE,GPA,MAJOR\nBill,18,4.0,CS\nMike,20,2.9,BS\nWill,20,2.4,CS\n'
    

    更新

    我将其更改为使用您的 cmets 进行更新。一些更新,如果文件不存在则创建文件,并且仍在使用您的 cmets 改进它。如果卡在无限循环中,可以按 CTRL-D。

    $ cat kd2.csv
    NAME AGE GPA MAJOR
    A 20 3.2 CIS
    B 31 4.0 CS
    C 34 3.5 CE
    D 18 2.0 CS
    E 4.0 3.2 CE
    
    import io
    
    def new_student_add():
      only_allowed = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
      stub = io.StringIO('NAME AGE GPA MAJOR\n')
      while True:
         try:
            df = pd.read_csv('kd4.csv', delim_whitespace=True, index_col=0) 
         except:
            stub.seek(0)
            df = pd.read_csv(stub, delim_whitespace=True, index_col=0)
         new_csv_dict = {}
         try:
            new_name =input('Please select the letter that matches your name from the following:  (A, B, C, D, E, F, G, H, I, J):  ')
         except:
            break
         if new_name not in only_allowed:
            print("Only letters in {} are allowed".format(only_allowed))
            continue
         if  new_name in df.index: 
            print("This name has already been used.")
            continue
         new_csv_dict['AGE'] =input('Please enter your Age: ')
         new_csv_dict['GPA'] =input('Please enter your GPA: ')
         new_csv_dict['MAJOR'] =input('Please select your major from the following (CS, CET, CIS, CE) ')
         df.loc[new_name] = new_csv_dict   
         break 
      df.to_csv(r'kd4.csv', sep=' ')
      return df 
    
    for x in range (0,9):
       df = new_student_add()
    
    
    for name, row in  df.iterrows(): 
      print("My name starts with the letter {} and I am {} years old. I study {} and my GPA is: {}".format(name, int(row['AGE']), row['MAJOR'], row['GPA']))
    
    # This may be much faster, so adding it in in case the author needs a faster algorithm. Thanks AlexanderCécile
    # for item in df.itertuples(): 
    # print(f"My name starts with the letter {item[0]} and I am {item[1]} years old. I study {item[3]} and my GPA is: {item[2]}")
    
    

    【讨论】:

    • 我不确定这是否与 OP 想要的功能相同。似乎他希望用户继续重试,直到他们找到可用的名称,不是吗?
    • 感谢您的帮助!我试过了,但@AlexanderCécile 是正确的。我需要让用户继续尝试,直到他们选择可用的“姓名/字母”
    • 看起来真不错!在函数中看到它会很好!所以最后代码应该: 要求用户输入一个与其姓名匹配的字母:(A,B,C,D,E,F,G,H,I,J),AGE,GPA(1-4 ) 和主要来自 (CS, CET, CIS, CE)。然后按如下方式打印这些信息: 我的名字以字母 (NAME) 开头,我 (AGE) 岁。我学习(专业),我的 GPA 是:(GPA)。对具有不同值的 10 个用户重复步骤 1(名称不能重复)。将输入的信息存储到 csv 文件中。
    • 不要使用iterrows,它有一些主要的缺点! itertuples 提供基本相同的功能,没有任何缺陷。例如,请参阅this post。另外,你为什么不使用 f-strings?
    • 这是一个简单的更改,如果 JPnova87 想看到它的使用方式,我可以更新它,代码如下:#for item in df.itertuples(): # print(f"My name starts带有字母 {item[0]},我是 {item[1]} 岁。我学习 {item[3]},我的 GPA 是:{item[2]}")
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多