【问题标题】:Create lists of anagrams from a list of words从单词列表创建字谜列表
【发布时间】:2015-07-26 14:15:55
【问题描述】:

我想从单词列表中找到创建字谜列表。我应该在代码中使用另一个循环还是递归?

some_list = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']

new_list = [some_list[0]]
i = 0
while i+1 < len(some_list):
    if (''.join(sorted(some_list[0]))) == (''.join(sorted(some_list[i+1]))):
        new_list.append(some_list[i+1])
        i = i+1
    else:
        i = i+1

print(new_list)

  • 我的输出是['bad', 'dab', 'bda', 'dba']。但我也想要更多的清单 来自some_list 的其他字谜。

我希望输出为: - ['app', 'ppa'] - ['bad', 'dab', 'bda', 'dba'] - ['sad', 'das']

【问题讨论】:

标签: python list anagram


【解决方案1】:

我建议您编写 Python,而不是 Java 或您在其中模拟的任何其他语言。这是您在 Python 中的核心代码,具有正常循环且没有所有不必要的内容:

new_list = [some_list[0]]
for word in some_list[1:]:
    if sorted(some_list[0]) == sorted(word):
        new_list.append(word)

我看不出递归有什么用,但是是的,您可以围绕它包裹一个外循环以查找其他字谜组。


虽然我会这样做,但使用有用的itertools.groupby

for _, group in groupby(sorted(some_list, key=sorted), sorted):
    group = list(group)
    if len(group) > 1:
        print(group)

打印出来的:

['bad', 'dab', 'bda', 'dba']
['sad', 'das']
['app', 'ppa']

对已更改问题进行分组排序的替代解决方案:

groups = (list(group) for _, group in groupby(sorted(some_list, key=sorted), sorted))
print([group for group in sorted(groups) if len(group) > 1])

输出:

[['app', 'ppa'], ['bad', 'dab', 'bda', 'dba'], ['sad', 'das']]

【讨论】:

  • 打印时,它不会按字母顺序打印列表,即; ['app', 'ppa'] ['bad', 'dab', 'bda', 'dba'] ['sad', 'das']
  • 是的。所以?您的问题中的 "I want the output to be:" 部分没有对其进行排序。
  • 一般来说,不是什么好事。您以这种方式使已发布的有效答案无效。你确定你现在有最终版本吗?在第二组中,您在“bda”之前有“dab”。
  • 是的。列表只需要按字母顺序打印。
  • 好的,我已经为此添加了解决方案。
【解决方案2】:

您的问题是您在列表中循环一次,因为您需要根据所有单词进行循环。

但我建议另一种方法来完成这项任务,您可以使用itertools.groupby 和使用operator.itemgetter 的排序功能:

some_list = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']

from operator import itemgetter
from itertools import groupby 
s=sorted([(i,''.join(sorted(j))) for i,j in enumerate(some_list)],key=itemgetter(1))
inds= [zip(*g)[0] for _,g in groupby(s,itemgetter(1))]
print [itemgetter(*i)(some_list) for i in inds]

结果:

[('bad', 'dab', 'bda', 'dba'), 'mad', ('sad', 'das'), ('app', 'ppa'), 'pge']

我在这里所做的只是使用sortedenumerate 创建一个带有这些索引的排序单词列表:

sorted([(i,''.join(sorted(j))) for i,j in enumerate(some_list)],key=itemgetter(1))
[(0, 'abd'), (4, 'abd'), (6, 'abd'), (9, 'abd'), (3, 'adm'), (2, 'ads'), (8, 'ads'), (1, 'app'), (7, 'app'), (5, 'egp')]

然后我们需要根据第二个元素对这些对进行分组并获取第一个元素(索引),因此我们将获得以下元组列表:

[(0, 4, 6, 9), (3,), (2, 8), (1, 7), (5,)]

每个元组都包含那些排序表示相同的单词的索引。

最后你只需要根据前面的索引选择主列表的元素:

[itemgetter(*i)(some_list) for i in inds]
[('bad', 'dab', 'bda', 'dba'), 'mad', ('sad', 'das'), ('app', 'ppa'), 'pge']

【讨论】:

  • @StefanPochmann 不,你可以从解释中理解逻辑很简单!
  • 我的意思是复杂的意思是你正在做很多你不需要的事情。无缘无故地访问索引并返回。
  • @StefanPochmann 是的,我不需要排序然后 grub 索引我可以简单地使用 sorted 作为键,我看到你编码的部分 key=sorted 是我错过的,你得到了我的投票为此!
【解决方案3】:

1) 创建一个函数anagrams(word),它像您的代码一样返回单个单词的字谜列表。
2) map 你的单词列表中的函数。

【讨论】:

  • “地图”是什么意思?
【解决方案4】:

这里有一个解决方案:

from itertools import groupby
some_list = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']
some_list_ordered = map( lambda x : "".join( sorted( x) ), some_list )
some_lists = sorted(zip( some_list_ordered, some_list ) )
anagrams = filter( lambda x : len( x ) > 1, [ zip(*v)[1]  for k,v in groupby( some_lists, lambda x : x[0] ) ] )    

for a in anagrams:
    print a

#('bad', 'bda', 'dab', 'dba')
#('das', 'sad')
#('app', 'ppa')

【讨论】:

    【解决方案5】:

    如果你能负担得起额外字典的内存开销,那么在我看来,这样做的自然方法是:

    words = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']
    
    anagrams = {}
    for word in words:
        sword = ''.join(sorted(word))
        try:
            anagrams[sword].append(word)
        except KeyError:
            anagrams[sword] = [word]
    
    anagrams_list = [v for v in anagrams.values() if len(v) > 1]
    print anagrams_list
    

    输出:

    [['app', 'ppa'], ['bad', 'dab', 'bda', 'dba'], ['sad', 'das']]
    

    编辑:如以下评论中所述,如果语法不打扰您,您可以将 try...except 块替换为 dict 方法 setdefault

    words = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']
    
    anagrams = {}
    for word in words:
        sword = ''.join(sorted(word))
        anagrams.setdefault(sword, []).append(word)
    
    anagrams_list = [v for v in anagrams.values() if len(v) > 1]
    print anagrams_list
    

    【讨论】:

    • 你知道list.setdefault吗?这可能会取代你的整个尝试/除外部分。
    • @StefanPochmann 我觉得这个语法有点令人不安,因为即使它被称为setdefault,你实际上是在得到一些东西,但我已经给出了一个替代方案。
    • 是的,最初我也觉得它有点混乱,但我已经习惯了:-)。尽管我仍然主要使用 defaultdict 代替,除非我有充分的理由不这样做。
    【解决方案6】:

    您可以对字典中的单词进行分组,使用排序后的单词作为键,过滤掉不包含至少两个元素的单词,使用OrderedDict 保持顺序:

    some_list = ['bad', 'app', 'sad', 'mad', 'dab','pge', 'bda', 'ppa', 'das', 'dba']
    
    
    from collections import OrderedDict
    
    od = OrderedDict()
    for ele in some_list:
        srt = "".join(sorted(ele))
        od.setdefault(srt,[]).append(ele)
    
    print(filter(lambda x: len(x) > 1, od.values()))
    
    
    [['bad', 'dab', 'bda', 'dba'], ['app', 'ppa'], ['sad', 'das']]
    

    或使用循环并附加到列表,使用临时列表收集常用词:

    new_list = []
    from collections import OrderedDict
    for ele in OrderedDict.fromkeys("".join(sorted(ele)) for ele in some_list):
        temp = []
        for s in some_list:
            if ele == ''.join(sorted(s)):
                temp.append(s)
        if len(temp) > 1:
            new_list.append(temp)
    

    如果顺序无关紧要,defaultdict 会更有效:

    from collections import defaultdict
    
    d = defaultdict(list)
    for ele in some_list:
        d[''.join(sorted(ele))].append(ele)
    
    print(filter(lambda x: len(x) > 1, d.values()))
    [['app', 'ppa'], ['bad', 'dab', 'bda', 'dba'], ['sad', 'das']]
    

    【讨论】:

      【解决方案7】:
      import java.util.*;
      
      public class GroupAnagramsTogether {
          public static void main(String[] args)
       {
              String [] input = new String [] {"bad", "app", "sad", "mad", "dab","pge", "bda", "ppa", "das", "dba"};
              System.out.println("Input: " + Arrays.toString(input));
      
              List<List<String>> result = groupAnagram(input);
              System.out.println(result);
          }
      
          private static List<List<String>> groupAnagram(String[] input) 
      {
              List<List<String>> list = new ArrayList<List<String>>();
              
              HashMap<String, List<String>> mp = new HashMap<String, List<String>>();
              
              for(String s : input)
              {
                  char[] ch = s.toCharArray();
                  Arrays.sort(ch);
                  
                  String key = new String(ch);
                  if(mp.containsKey(key))
                  {
                      mp.get(key).add(s);
                  }
                  else
                  {
                      List<String> strList = new ArrayList<String>();
                      strList.add(s);
                      mp.put(key,strList);
                  }
              }
              list.addAll(mp.values());
              return list;
          }
      
      }
      

      【讨论】:

      • 问题是使用python,而这是java。
      猜你喜欢
      • 2011-09-19
      • 1970-01-01
      • 2021-08-27
      • 2019-06-25
      • 1970-01-01
      • 2017-10-09
      • 2017-07-02
      • 2011-09-07
      • 1970-01-01
      相关资源
      最近更新 更多