以自定义方式对数组进行排序的算法

发布于 2024-11-17 04:17:48 字数 1220 浏览 1 评论 0原文

我正在寻找一种以自定义方式对数组进行排序的算法,但我没有成功找到解决问题的正确方法。我将使用类似 Django 的语法来描述代码,但没有必要仅限于 Django 的解决方案。

假设我有以下模型(类):

class Website(models.Model):
    ...
class Offer(models.Model):
    website = models.ForeignKey(Website, on_delete=models.CASCADE)
    ...

假设我有以下实例:

  • Offer 1 ->网站 A
  • 报价 2 ->网站 B
  • 报价 3 ->网站 B
  • 报价 4 ->网站 B
  • 报价 5 ->网站 C
  • 优惠 6 ->网站 A
  • 报价 7 ->网站 A
  • 报价 8 ->网站 C

此实例形成一个序列(数组):

sequence = [Offer 1, Offer 2, Offer 3, Offer 4, Offer 5, Offer 6, Offer 7, Offer 8]

我需要按照优惠的方式对序列进行排序同一网站不能依次排列,但原始订单应尽可能保持相同。

因此,排序顺序应如下所示:

sequence = [Offer 1, Offer 2, Offer 5, Offer 3, Offer 6, Offer 4, Offer 7, Offer 8]

正例:

  • 网站 A、网站 B、网站 A、网站 C、网站 A
  • 网站 A、网站 B、网站 C、网站 B、网站 C
  • 网站 A、网站 B、网站 A、网站 B、网站 A

负面示例:

  • 网站 A、网站 B、网站 B、网站 A、网站 B、...
  • 网站 B、网站 C、网站 A、网站 A 、网站B、...
  • 网站B、网站C、网站A、网站C、网站 C,...

感谢您的任何建议。

I was looking for an algorithm for sorting an array in a custom way but I didn't succeed in finding the proper solution to my problem. I'll describe the code in Django-like syntax but it's not necessary to limit a solution only for Django.

Let's suppose I have the following models (classes):

class Website(models.Model):
    ...
class Offer(models.Model):
    website = models.ForeignKey(Website, on_delete=models.CASCADE)
    ...

And let's suppose I have the following instances:

  • Offer 1 -> Website A
  • Offer 2 -> Website B
  • Offer 3 -> Website B
  • Offer 4 -> Website B
  • Offer 5 -> Website C
  • Offer 6 -> Website A
  • Offer 7 -> Website A
  • Offer 8 -> Website C

This instances form a sequence (array):

sequence = [Offer 1, Offer 2, Offer 3, Offer 4, Offer 5, Offer 6, Offer 7, Offer 8]

I need to sort the sequence in the way where Offers with the same Website cannot stand one after another nevertheless the original order should stay as same as possible.

So the sorted sequence should look this way:

sequence = [Offer 1, Offer 2, Offer 5, Offer 3, Offer 6, Offer 4, Offer 7, Offer 8]

Positive Examples:

  • Website A, Website B, Website A, Website C, Website A
  • Website A, Website B, Website C, Website B, Website C
  • Website A, Website B, Website A, Website B, Website A

Negative Examples:

  • Website A, Website B, Website B, Website A, Website B, ...
  • Website B, Website C, Website A, Website A, Website B, ...
  • Website B, Website C, Website A, Website C, Website C, ...

Thanks for any suggestion.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海螺姑娘 2024-11-24 04:17:48

试试这个:

def sort_custom(offers):
    sorted_offers, sorted_count, index = [], len(offers), 0
    while sorted_count > 0:
        item = offers[index]
        if not sorted_offers or sorted_offers[-1] != item:
            sorted_offers.append(item)
            sorted_count -= 1
            del offers[index]
            if index > 0: index = 0
        else:
            if index < len(offers) - 1:
                index += 1
            else:
                sorted_offers += offers
                break
    return sorted_offers

用法:

>> lst = ['A', 'B', 'B', 'B', 'C', 'A', 'A', 'C']
>> sort_custom(lst)
['A', 'B', 'C', 'B', 'A', 'B', 'A', 'C']
>> lst2 = ['C', 'A', 'C', 'A', 'C', 'A', 'A', 'A']
>> sort_custom(lst2)
['C', 'A', 'C', 'A', 'C', 'A', 'A', 'A']

时间:

>> # for lst = ['A', 'B', 'B', 'B', 'C', 'A', 'A', 'C']
>> timer.repeat(3, 2000000)
[0.4880218505859375, 0.4770481586456299, 0.4776880741119385]

Try this:

def sort_custom(offers):
    sorted_offers, sorted_count, index = [], len(offers), 0
    while sorted_count > 0:
        item = offers[index]
        if not sorted_offers or sorted_offers[-1] != item:
            sorted_offers.append(item)
            sorted_count -= 1
            del offers[index]
            if index > 0: index = 0
        else:
            if index < len(offers) - 1:
                index += 1
            else:
                sorted_offers += offers
                break
    return sorted_offers

Usage:

>> lst = ['A', 'B', 'B', 'B', 'C', 'A', 'A', 'C']
>> sort_custom(lst)
['A', 'B', 'C', 'B', 'A', 'B', 'A', 'C']
>> lst2 = ['C', 'A', 'C', 'A', 'C', 'A', 'A', 'A']
>> sort_custom(lst2)
['C', 'A', 'C', 'A', 'C', 'A', 'A', 'A']

timing:

>> # for lst = ['A', 'B', 'B', 'B', 'C', 'A', 'A', 'C']
>> timer.repeat(3, 2000000)
[0.4880218505859375, 0.4770481586456299, 0.4776880741119385]
写给空气的情书 2024-11-24 04:17:48

这应该可行:

def gen_best_order(orig):
    last = None
    while len(orig) > 0:
        deli = None
        for i, m in enumerate(orig):
            if m.website != last.website:
                last = m
                deli = i
                yield m
                break
        if deli is None:
            last = orig[0]
            yield orig[0]
            deli = 0
        del orig[deli]
ordered = list(gen_best_order(sequence))

这是一个生成器,它将尝试按顺序生成元素,但如果下一个元素等于生成的最后一个元素,它将跳过它。如果它到达列表的末尾并且没有办法产生不等于前一个的东西,它无论如何都会产生它。

这是一个处理数字列表的示例:

def gen_best_order(orig):
    last = None
    while len(orig) > 0:
        deli = None
        for i, m in enumerate(orig):
            if m != last:
                last = m
                deli = i
                yield m
                break
        if deli is None:
            last = orig[0]
            yield orig[0]
            deli = 0
        del orig[deli]

nums = [1,2,3,3,4,5,5]        
print 'orig:', nums
print 'reordered:', list(gen_best_order(nums))

这将打印:

orig: [1, 2, 3, 3, 4, 5, 5]
reordered: [1, 2, 3, 4, 3, 5, 5]

This should work:

def gen_best_order(orig):
    last = None
    while len(orig) > 0:
        deli = None
        for i, m in enumerate(orig):
            if m.website != last.website:
                last = m
                deli = i
                yield m
                break
        if deli is None:
            last = orig[0]
            yield orig[0]
            deli = 0
        del orig[deli]
ordered = list(gen_best_order(sequence))

This is a generator that will try and yield elements in order, but if the next element equals the last element yielded, it will skip it. If it gets to the end of the list and there is no way to yield something that doesn't equal the previous, it just yields it anyway.

Here's an example of it working on a list of numbers:

def gen_best_order(orig):
    last = None
    while len(orig) > 0:
        deli = None
        for i, m in enumerate(orig):
            if m != last:
                last = m
                deli = i
                yield m
                break
        if deli is None:
            last = orig[0]
            yield orig[0]
            deli = 0
        del orig[deli]

nums = [1,2,3,3,4,5,5]        
print 'orig:', nums
print 'reordered:', list(gen_best_order(nums))

This prints:

orig: [1, 2, 3, 3, 4, 5, 5]
reordered: [1, 2, 3, 4, 3, 5, 5]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文