【问题标题】:Python: how to sort a list of strings by substring relevance?Python:如何按子字符串相关性对字符串列表进行排序?
【发布时间】:2018-05-20 19:38:32
【问题描述】:

我有一些字符串列表,例如:

["foo bar SOME baz TEXT bob",
"SOME foo bar baz bob TEXT",
"SOME foo TEXT",
"foo bar SOME TEXT baz",     
"SOME TEXT"]

我希望它按SOME TEXT 子字符串的精确度排序(大写无关紧要)。像这样的顺序:

["SOME TEXT",
"foo bar SOME TEXT baz",
"SOME foo TEXT",
"foo bar SOME baz TEXT bob",
"SOME foo bar baz bob TEXT"]

这个想法是 - 最好的分数得到与子字符串单词位置最匹配的字符串。对于子字符串单词之间的“草率”单词数量更大 - 它得到的排序越低。

我找到了一些库,例如 fuzzysetLevenshtein distance,但我不确定这是我需要的。据我了解,我通过我想要排序的内容知道确切的子字符串,并且这些库搜索相似的单词。

实际上,我需要在我的 Django 项目中进行一些数据库查询(Postgresql)之后进行这种排序。我已经尝试过使用它的 ORM 进行全文搜索,但没有得到这个相关的排序顺序(它不计算子字符串之间的距离)。接下来我尝试了 Haystack+Whoosh,但此时也没有找到如何在那里进行这种排序的信息。所以现在的想法是获取查询集,然后将其从数据库中排序(是的,我知道这可能是一个糟糕的决定,但现在我希望它能够正常工作)。但是,如果有人告诉我如何在任何技术中做到这一点,我已经在这里提到过——那也将非常酷。谢谢!

附言子串的长度应该是 2-10 个字,最多 20 个字的字符串。

【问题讨论】:

    标签: python sorting


    【解决方案1】:

    您可以使用difflib.SequenceMatcher 来实现与您想要的输出非常相似的东西:

    >>> import difflib
    >>> l = ["foo bar SOME baz TEXT bob", "SOME foo bar baz bob TEXT", "SOME foo TEXT", "foo bar SOME TEXT baz", "SOME TEXT"]
    >>> sorted(l, key=lambda z: difflib.SequenceMatcher(None, z, "SOME TEXT").ratio(), reverse=True)
    ['SOME TEXT', 'SOME foo TEXT', 'foo bar SOME TEXT baz', 'foo bar SOME baz TEXT bob', 'SOME foo bar baz bob TEXT']
    

    如果您不能分辨出唯一的区别是 "foo bar SOME TEXT baz""SOME foo TEXT" 两个元素的位置与您想要的输出相比交换了。

    【讨论】:

    • 这是一个我不知道的有趣课程。 +1。
    • 是的,这很完美!谢谢! p.s.顺便说一句 difflib 是我找到的第三个库,但在这里忘记提及它(也没有得到如何正确使用它)。 :)
    【解决方案2】:

    这是我的看法。

    l = ["foo bar SOME baz TEXT bob",
    "SOME foo bar baz bob TEXT",
    "SOME foo TEXT",
    "foo bar SOME TEXT baz",     
    "SOME TEXT"]
    
    l.sort(key=lambda x: (x.find("SOME")-x.find("TEXT"))*0.9-0.1*x.find("SOME"), reverse=True)
    
    print(l)
    

    输出:

    ['SOME TEXT', 'foo bar SOME TEXT baz', 'SOME foo TEXT', 'foo bar SOME baz TEXT bob', 'SOME foo bar baz bob TEXT']
    

    所以我们所做的是根据“SOME”和“TEXT”之间的距离的主要权重和字符串中出现“SOME”的一些次要权重对列表进行排序。

    另一种更长的方法是首先根据 SOME 和 TEXT 之间的距离对列表进行分组。然后根据“SOME”的位置对每个组进行排序。

    【讨论】:

    • 那些 0.9-0.1 是什么意思?这怎么能与 3+ 个单词的子字符串一起使用?
    【解决方案3】:

    见您友好的邻居sorting tutorial。你需要一个带键的排序。这是一个简单的功能,可以为您提供想法;它找到两个单词之间的距离,并将其作为差异度量返回。

    sentence = ["foo bar SOME baz TEXT bob",
                "SOME foo bar baz bob TEXT",
                "SOME foo TEXT",
                "foo bar SOME TEXT baz",
                "SOME TEXT"]
    
    def match_score(sentence):
        some_pos = sentence.find("SOME")
        text_pos = sentence.find("TEXT")
        return abs(text_pos - some_pos)
    
    sentence.sort(key = lambda x: match_score(x))
    
    for item in sentence:
        print(item)
    

    输出:

    foo bar SOME TEXT baz
    SOME TEXT
    foo bar SOME baz TEXT bob
    SOME foo TEXT
    SOME foo bar baz bob TEXT
    

    【讨论】:

      猜你喜欢
      • 2012-11-26
      • 2021-06-10
      • 2014-08-30
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 2018-07-02
      • 2021-10-13
      • 2020-03-07
      相关资源
      最近更新 更多