【问题标题】:comparing two lists and searching by a field, Python比较两个列表并按字段搜索,Python
【发布时间】:2017-01-29 21:17:49
【问题描述】:

我希望比较两个文件,然后生成特定的输出:

1) 下面是用户名文本文件的内容(这里存储了用户最近看过的电影)

    Sci-Fi,Out of the Silent Planet
    Sci-Fi,Solaris
    Romance, When Harry met Sally

2) 以下是films.txt 文件的内容,该文件存储了程序中可供用户使用的所有电影

0,Genre, Title, Rating, Likes
1,Sci-Fi,Out of the Silent Planet, PG,3
2,Sci-Fi,Solaris, PG,0
3,Sci-Fi,Star Trek, PG,0
4,Sci-Fi,Cosmos, PG,0
5,Drama, The English Patient, 15,0
6,Drama, Benhur, PG,0
7,Drama, The Pursuit of Happiness, 12, 0
8,Drama, The Thin Red Line, 18,0
9,Romance, When Harry met Sally, 12, 0
10,Romance, You've got mail, 12, 0
11,Romance, Last Tango in Paris, 18, 0
12,Romance, Casablanca, 12, 0

我需要的输出示例:用户当前观看了两部科幻片和一部爱情片。因此,输出应按类型搜索电影文本文件(标识 SCI-FI 和 ROMANCE),并应在films.txt 文件中列出用户尚未观看的电影。在这种情况下

3,Sci-Fi,Star Trek, PG,0
4,Sci-Fi,Cosmos, PG,0
10,Romance, You've got mail, 12, 0
11,Romance, Last Tango in Paris, 18, 0
12,Romance, Casablanca, 12, 0

我有以下代码尝试执行上述操作,但它产生的输出不正确:

def viewrecs(username):
   #set the username variable to the text file -to use it in the next bit
   username = (username + ".txt")
   #open the username file that stores latest viewings
   with open(username,"r") as f:
      #open the csv file reader for the username file
          fReader=csv.reader(f)
          #for each row in the fReader
          for row in fReader:
             #set the genre variable to the row[0], in which row[0] is all the genres (column 1 in username file)
             genre=row[0]
             #next, open the films file
             with open("films.txt","r") as films:
                #open the csv reader for this file (filmsReader as opposed to fReader)
                filmsReader=csv.reader(films)
                #for each row in the films file
                for row in filmsReader:
                   #and for each field in the row 
                   for field in row:
                      #print(field)
                      #print(genre)
                      #print(field[0])
                      if genre in field and row[2] not in fReader:
                         print(row)

输出(不需要的):

['1', 'Sci-Fi', 'Out of the Silent Planet', ' PG', '3']
['2', 'Sci-Fi', 'Solaris', ' PG', '0']
['3', 'Sci-Fi', 'Star Trek', ' PG', '0']
['4', 'Sci-Fi', 'Cosmos', ' PG', '0']

我不想要重写或新的解决方案,但最好是修复上述解决方案的逻辑进展......

@gipsy - 您的解决方案似乎几乎奏效了。我用过:

def viewrecs(username):

  #set the username variable to the text file -to use it in the next bit
  username = (username + ".txt")
  #open the username file that stores latest viewings
  lookup_set = set()
  with open(username,"r") as f:
    #open the csv file reader for the username file
    fReader=csv.reader(f)
    #for each row in the fReader
    for row in fReader:
      genre = row[1]
      name = row[2]
      lookup_set.add('%s-%s' % (genre, name))
  with open("films.txt","r") as films:
    filmsReader=csv.reader(films)
    #for each row in the films file
    for row in filmsReader:
      genre = row[1]
      name = row[2]
      lookup_key = '%s-%s' % (genre, name)
      if lookup_key not in lookup_set:
        print(row)

输出如下:它正在打印所有电影中不在第一组中的所有行,而不仅仅是基于第一组中基于 GENRE 的行:

['0', 'Genre', ' Title', ' Rating', ' Likes']
['3', 'Sci-Fi', 'Star Trek', ' PG', ' 0']
['4', 'Sci-Fi', 'Cosmos', ' PG', ' 0']
['5', 'Drama', ' The English Patient', ' 15', ' 0']
['6', 'Drama', ' Benhur', ' PG', ' 0']
['7', 'Drama', ' The Pursuit of Happiness', ' 12', ' 0']
['8', 'Drama', ' The Thin Red Line', ' 18', ' 0']
['10', 'Romance', " You've got mail", ' 12', ' 0']
['11', 'Romance', ' Last Tango in Paris', ' 18', ' 0']
['12', 'Romance', ' Casablanca', ' 12', ' 0']

注意:为简单起见,我将第一组的格式更改为与所有电影条目相同:

1,Sci-Fi,Out of the Silent Planet, PG
2,Sci-Fi,Solaris, PG

【问题讨论】:

    标签: python list compare


    【解决方案1】:

    如何使用集合和单独的列表来过滤未看过的适当类型的电影?我们甚至可以为此滥用字典的keysvalues

    def parse_file (file):
        return map(lambda x: [w.strip() for w in x.split(',')], open(file).read().split('\n'))
    
    def movies_to_see ():
        seen = {film[0]: film[1] for film in parse_file('seen.txt')}
        films = parse_file('films.txt')
        to_see = []
    
        for film in films:
            if film[1] in seen.keys() and film[2] not in seen.values():
                to_see.append(film)
        return to_see 
    

    【讨论】:

    • movies_to_see 是方法,to_see 是它返回的数组。
    • 我不熟悉 lambda 和地图的使用,因此,再次注释每一行会很有帮助。我会尝试这个,但在哪里实现它以及它的含义并不明显......
    • 解析文件只产生一个列表列表,其中每个子列表都是从作为参数接收的文件中以逗号分隔的行,movies_to_see 通过您的帖子返回您想要的输出
    【解决方案2】:

    使用str.split()str.join()函数的解决方案:

    # change file paths with your actual ones
    with open('./text_files/user.txt', 'r') as userfile:
        viewed = userfile.read().split('\n')
        viewed_genders = set(g.split(',')[0] for g in viewed)
    
    with open('./text_files/films.txt', 'r') as filmsfile:
        films = filmsfile.read().split('\n')
        not_viewed = [f for f in films
                      if f.split(',')[1] in viewed_genders and ','.join(f.split(',')[1:3]) not in viewed]
    
    print('\n'.join(not_viewed))
    

    输出:

    3,Sci-Fi,Star Trek, PG,0
    4,Sci-Fi,Cosmos, PG,0
    10,Romance, You've got mail, 12, 0
    11,Romance, Last Tango in Paris, 18, 0
    12,Romance, Casablanca, 12, 0
    

    【讨论】:

    • 你能评论每一行的代码以及它在做什么 - 这对于理解逻辑最有帮助。此外,在尝试完全按照您的建议进行操作时,会出现以下错误;如果 f.split(',')[1] inviewed_genres 和 ','.join(f.split(',')[1:3]) 未查看] IndexError: list index out of range
    • @pythoncarrot,应该没有任何错误,我已经在您发布的内容上对其进行了测试 - 它工作正常。检查您的代码是否有错误,同时检查您的某些文件中是否有额外的列。
    • 错误仍然存​​在:如果 f.split(',')[1] inviewed_genres 和 ','.join(f.split(',')[1:3]) 不在查看中] IndexError: 列表索引超出范围
    • 只有当这些文件的实际内容与您发布的内容不同时,才会出现此类错误。发布实际内容,或从文件中删除多余的空格
    【解决方案3】:

    好的,通过第一个文件构建一个集合,以 Genre + name 作为条目。

    现在遍历第二个文件并在上面创建的集合中查找 Genre+ 名称的条目,如果不存在则打印出来。

    回家后,我可以输入一些代码。

    正如我所承诺的,我的代码如下:

    def viewrecs(username):
      #set the username variable to the text file -to use it in the next bit
      username = (username + ".txt")
      # In this set we will collect the unique combinations of genre and name
      genre_name_lookup_set = set()
      # In this set we will collect the unique genres 
      genre_lookup_set = set()
      with open(username,"r") as f:
        #open the csv file reader for the username file
        fReader=csv.reader(f)
        #for each row in the fReader
        for row in fReader:
          genre = row[0]
          name = row[1]
          # Add the genre name combination to this set, duplicates will be taken care automatically as set won't allow dupes  
          genre_name_lookup_set.add('%s-%s' % (genre, name))
          # Add genre to this set
          genre_lookup_set.add(genre)
      with open("films.txt","r") as films:
        filmsReader=csv.reader(films)
        #for each row in the films file
        for row in filmsReader:
          genre = row[1]
          name = row[2]
          # Build a lookup key using genre and name, example:Sci-Fi-Solaris
          lookup_key = '%s-%s' % (genre, name)
          if lookup_key not in genre_name_lookup_set and genre in genre_lookup_set:
            print(row)
    

    【讨论】:

    • 您能否提供代码以使该答案易于理解。流派 = 流派?非常感谢
    • 抱歉打错了。是的。我的意思是流派。
    • @pythoncarrot 我的答案已用代码更新。请看一下
    • 谢谢 - 但是,在尝试您的代码时出现以下错误:lookup_set.add('%-%' % (genre, name)) TypeError: not all arguments convert during string formatting *另外,你能解释一下 "('%-%' %" 位的作用吗?
    • 成功了!几乎....我不得不在每个 % 之后添加一个“s”来调整我之前遇到的格式问题。现在的问题是在电影文件中打印不在初始查找集中的每一部电影......不仅仅是基于初始集中类型的那些
    猜你喜欢
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-30
    相关资源
    最近更新 更多