使列表尽可能未排序的功能

分享于2022年07月17日 algorithm python sorting 问答
【问题标题】:使列表尽可能未排序的功能(Function to make a list as unsorted as possible)
【发布时间】:2022-01-27 04:24:22
【问题描述】:

我正在寻找一个函数来使列表尽可能地未排序。最好在 Python 中。

背景故事:

我想检查 URL 状态并查看 URL 是否给出 404。我只使用 asyncio requests 模块。没什么特别的。

现在我不想让服务器过载,所以我想尽量减少同时检查同一域中的 URL。我的想法是对 URL 进行排序,使彼此接近的项目(具有相同的排序键 = 域名)在列表中尽可能远离。

数字示例:

a=[1,1,2,3,3]  # <== sorted list, sortness score = 2
   0,1,2,3,4   # <== positions

可能未排序为:

b=[1,3,2,1,3]  # <== unsorted list, sortness score = 6
   0,1,2,3,4   # <== positions

我想说,我们可以通过将相等项目(具有相同的键 = 域名)之间的距离相加来计算排序分数。更高的排序意味着更好的未排序。也许有更好的方法来测试 unsortness。

列表 a 的排序分数为 2。1 的距离总和为 (1-0)=1,2 为 0,3 为 (4-3)=1。

列表 b 的排序分数为 6。1 的距离总和为 (3-0)=3,2 为 0,3 为 (4-1)=3。

URL 列表看起来像(域,URL)元组列表:

[
   ('example.com', 'http://example.com/404'),
   ('test.com', 'http://test.com/404'),
   ('test.com', 'http://test.com/405'),
   ('example.com', 'http://example.com/405'),
   ...
]

我正在开发一个可以正常工作的原型,但不是最佳的,因为我可以找到一些最好手动未分类的变体。

有人想试试吗?

This is my code ,但不是很好:):

from collections import Counter
from collections import defaultdict
import math


def test_unsortness(lst:list) -> float:
    pos = defaultdict(list)
    score = 0
    # Store positions for each key
    # input = [1,3,2,3,1] => {1: [0, 4], 3: [1, 3], 2: [2]}
    for c,l in enumerate(lst):
        pos[l].append(c)
    for k,poslst in pos.items():
        for i in range(len(poslst)-1):
            score += math.sqrt(poslst[i+1] - poslst[i])
    return score


def unsort(lst:list) -> list:
    free_positions = list(range(0,len(lst)))
    output_list = [None] * len(free_positions)
    for val, count in Counter(lst).most_common():
        pos = 0
        step = len(free_positions) / count
        for i in range(count):
            output_list[free_positions[int(pos)]] = val
            free_positions[int(pos)] = None  # Remove position later
            pos = pos + step
        free_positions = [p for p in free_positions if p]
    return output_list


lsts = list()
lsts.append( [1,1,2,3,3] )
lsts.append( [1,3,2,3,1] )       # This has the worst score after unsort()
lsts.append( [1,2,3,0,1,2,3] )   # This has the worst score after unsort()
lsts.append( [3,2,1,0,1,2,3] )   # This has the worst score after unsort()
lsts.append( [3,2,1,3,1,2,3] )   # This has the worst score after unsort()
lsts.append( [1,2,3,4,5] )

for lst in lsts:
    ulst = unsort(lst)
    print( ( lst, '%.2f'%test_unsortness(lst), '====>', ulst, '%.2f'%test_unsortness(ulst), ) )

#  Original               score             Unsorted               score
#  -------                -----             --------               -----
# ([1, 1, 2, 3, 3],       '2.00',  '====>', [1, 3, 1, 3, 2],       '2.83')
# ([1, 3, 2, 3, 1],       '3.41',  '====>', [1, 3, 1, 3, 2],       '2.83')
# ([1, 2, 3, 0, 1, 2, 3], '6.00',  '====>', [1, 2, 3, 1, 2, 3, 0], '5.20')
# ([3, 2, 1, 0, 1, 2, 3], '5.86',  '====>', [3, 2, 1, 3, 2, 1, 0], '5.20')
# ([3, 2, 1, 3, 1, 2, 3], '6.88',  '====>', [3, 2, 3, 1, 3, 2, 1], '6.56')
# ([1, 2, 3, 4, 5],       '0.00',  '====>', [1, 2, 3, 4, 5],       '0.00')

附言。我不只是在寻找随机化功能,而且我知道有可以管理域负载的爬虫,但这是为了练习。

  • 令人惊讶的是,有一个问题似乎与此主题完全相关 cs.stackexchange.com/questions/11836/how-to-measure-sortedness
  • 您将 URL 粘贴在字典中如何(多映射、列表列表、使用域名作为键),然后线性地遍历键,沿途删除项目?跨度>
  • 我同意@FilipMilovanović,循环法似乎最简单
  • 您的“未分类”分数是否代表了您的真正目标,还是只是方便?在实际查询域时, [3, 2, 1, 0, 1, 2, 3] 的模式真的比 [1, 2, 3, 0, 1, 2, 3] 更好吗?如果目标是“传播事物”,那么将 100 和 50 的 1 分开可能比每个约 3 的 51 更差,尽管两者都是 150 与您的文本度量。 (当然,您可以找到更好的设置,但查看极端情况可以帮助衡量指标是否指定错误。)- P.S. “排序”在这里有点用词不当,因为您并不真正关心总排序。

【解决方案1】:

与其取消对 URL 列表的排序,为什么不按域对它们进行分组,每个都在队列中,然后异步处理它们,中间有延迟(随机?)?

在我看来,它不像您为实现相同目标而尝试做的那样复杂,如果您有很多域,那么您总是可以在那时限制并发运行的数量。

  • 你的观点非常好。但这更像是一个评论而不是一个答案。
  • 我想说 OP 正在询问如何不使他想要发送请求的服务器过载,所以我的回答是,不要做你想做的事,因为它看起来过于复杂出于需要,这里有一个替代方案。听起来对我来说是一个有效的答案?
  • @IsaacRabinovitch 的目标不是取消对列表的排序,不管这意味着什么,而是不要让服务器超载。这个答案是迄今为止最简单,最干净的方法。相比之下,使用庞大而复杂的优化库,对于大型列表性能较差,这是荒谬的。
  • @EricDuminil 即使取消排序不是解决 OP 问题的最实用方法,我仍然认为这本身就是一个有趣的问题。
  • 我投了赞成票,但比这要复杂一些。如果您说 domain1 有 100 个条目,然后是 50 个域,每个条目有 2 个条目,那么您几乎会立即在 domain1 上完全运行。理想情况下,通过此设置,您希望将 domain1 网址与来自 50 个域中的任何一个的条目“夹在中间”,这些域都没有超载的风险。