通过Python查找和分组字谜

时间:2011-11-18 11:16:52

标签: python list-comprehension anagram

input: ['abc', 'cab', 'cafe', 'face', 'goo']
output: [['abc', 'cab'], ['cafe', 'face'], ['goo']]

问题很简单:它按 anagrams 进行分组。订单无关紧要。

当然,我可以通过C ++(这是我的母语)来做到这一点。但是,我想知道这可以通过 Python 单行中完成。 编辑:如果不可能,可能是2或3行。我是Python的新手。

为了检查两个字符串是否是字谜,我使用了排序。

>>> input = ['abc', 'cab', 'cafe', 'face', 'goo']
>>> input2 = [''.join(sorted(x)) for x in input]
>>> input2
['abc', 'abc', 'acef', 'acef', 'goo']

我认为通过组合map左右可能是可行的。但是,我需要使用dict作为哈希表。我还不知道这是否可以在一行中完成。任何提示都会被贬低!

7 个答案:

答案 0 :(得分:6)

可读的单行解决方案:

output = [list(group) for key,group in groupby(sorted(words,key=sorted),sorted)]

例如:

>>> words = ['abc', 'cab', 'cafe', 'goo', 'face']
>>> from itertools import groupby
>>> [list(group) for key,group in groupby(sorted(words,key=sorted),sorted)]
[['abc', 'cab'], ['cafe', 'face'], ['goo']]

这里的关键是使用itertools.groupby from the itertools module将列表中的项目组合在一起。

我们提供给groupby的列表必须先进行排序,然后我们将其传递给sorted(words,key=sorted)。这里的诀窍是sorted可以接受一个关键函数,并根据这个函数的输出进行排序,所以我们再次传递sorted作为关键函数,这将使用字母对字母进行排序。字符串按顺序排列。无需定义我们自己的功能或创建lambda

groupby使用一个关键函数来判断项目是否应该组合在一起,我们可以再次将内置的sorted函数传递给它。

最后要注意的是输出是键对和组对象的对,所以我们只需要使用grouper对象并使用list函数将每个对象转换为列表。

(顺便说一句 - 我不会将你的变量input称为隐藏the built-in input function,尽管它可能不是你应该使用的那个。)

答案 1 :(得分:3)

难以理解的单线解决方案:

>>> import itertools
>>> input = ['abc', 'face', 'goo', 'cab', 'cafe']
>>> [list(group) for key,group in itertools.groupby(sorted(input, key=sorted), sorted)]
[['abc', 'cab'], ['cafe', 'face'], ['goo']]

(好吧,如果算上导入,那真是2行......)

答案 2 :(得分:2)

不是单行而是解决方案......

d = {}
for item in input:
  s = "".join(sorted(item))
  if not d.has_key(s):
    d[s] = []
  d[s].append(item)
input2 = d.values()

答案 3 :(得分:2)

可读版本:

from itertools import groupby
from operator import itemgetter

def norm(w):
  return "".join(sorted(w))

words = ['abc', 'cba', 'gaff', 'ffag', 'aaaa']

words_aug = sorted((norm(word), word) for word in words)

grouped = groupby(words_aug, itemgetter(0))

for _, group in grouped:
  print map(itemgetter(1), group)

单线:

print list(list(anagrams for _, anagrams in group) for _, group in groupby(sorted(("".join(sorted(word)), word) for word in words), itemgetter(0)))

打印:

[['aaaa'], ['abc', 'cba'], ['ffag', 'gaff']]

答案 4 :(得分:1)

from itertools import groupby

words = ['oog', 'abc', 'cab', 'cafe', 'face', 'goo', 'foo']

print [list(g) for k, g in groupby(sorted(words, key=sorted), sorted)]

<强>结果:

[['abc', 'cab'], ['cafe', 'face'], ['foo'], ['oog', 'goo']]

您不能只使用groupby函数,因为它只将您的键函数产生相同结果的顺序元素组合在一起。

简单的解决方案就是首先使用与分组相同的功能对单词进行排序。

答案 5 :(得分:0)

Dave的答案很简洁,但O(n log(n))所需的排序是from collections import defaultdict def group_anagrams(strings): m = defaultdict(list) for s in strings: m[tuple(sorted(s))].append(s) return list(m.values()) 操作。 更快的解决方案是:

int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0,
consonantCnt=0;

int ffCnt = 0, flCnt = 0, fiCnt = 0;

int spaceCnt = 0, newlCnt = 0, tabCnt = 0;

char *check = new char[100];

while ( cin >> check ) {

for ( int ix = 0; ix < strlen(check); ++ix ) {

 switch ( check[ix] ) {
    case 'a': case 'A':
      ++aCnt;
      break;
    case 'e': case 'E':
      ++eCnt;
      break;
    case 'i': case 'I':
      ++iCnt;
      break;
    case 'o': case 'O':
      ++oCnt;
      break;
    case 'u': case 'U':
      ++uCnt;
      break;
    case ' ':
      ++spaceCnt;
      break;
    case '\t':
      ++tabCnt;
      break;
    case '\n':
      ++newlCnt;
      break;
    default:
      if ( isalpha( check[ix] ) )
          ++consonantCnt;
      break;
}

  if ( check[ix] == 'f' ) {
    ++ix;
       switch ( check[ix] ) {
           case 'f':
              ++consonantCnt;
              ++ffCnt;
              break;
            case 'i':
              ++fiCnt;
              ++iCnt;
              break;
            case 'l':
              ++consonantCnt;
              ++flCnt;
              break;
            case 'I':
              ++iCnt;
              break;
            case 'a': case 'A':
              ++aCnt;
              break;
            case 'e': case 'E':
              ++eCnt;
              break;
            case 'o': case 'O':
              ++oCnt;
              break;
            case 'u': case 'U':
              ++uCnt;
              break;
            case ' ':
              ++spaceCnt;
              break;
            case '\t':
              ++tabCnt;
              break;
            case '\n':
              ++newlCnt;
              break;

            default:
               if ( isalpha( check[ix] ) )
               ++consonantCnt;
               break;
      }    
    } 
  }
}

delete [] check;

cout << "Встретилась a: \t" << aCnt << '\n'
<< "Встретилась e: \t" << eCnt << '\n'
<< "Встретилась i: \t" << iCnt << '\n'
<< "Встретилась o: \t" << oCnt << '\n'
<< "Встретилась u: \t" << uCnt << '\n'
<< "Встретилось согласных: \t" << consonantCnt << '\n'
<< "Встретилось fl: \t" << flCnt << '\n'
<< "Встретилось fi: \t" << fiCnt << '\n'
<< "Встретилось ff: \t" << ffCnt << '\n'
<< "Встретилось символов табуляции: \t" << ffCnt << '\n'
<< "Встретилось символов пробела: \t" << ffCnt << '\n'
<< "Встретилось символов новой строки: \t" << ffCnt << '\n'
<< '\n';

答案 6 :(得分:0)

只是稍微简化了先前的工作答案,以使它更具“可读性”(提取已排序的(单词...),但步骤更简单:

    >>> words = ['abc', 'eat', 'face', 'cab', 'tea', 'goo']
    >>> words = sorted(words, key=sorted)
    >>> words
    ['abc', 'cab', 'face', 'eat', 'tea', 'goo']
    >>> [list(group) for key,group in groupby(words, sorted)]
    [['abc', 'cab'], ['face'], ['eat', 'tea'], ['goo']]

按照 groupby 的预期,该序列处于排序顺序。