开发者

Algorithm for sorting an array in a custom way

开发者 https://www.devze.com 2023-03-14 12:56 出处:网络
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 nece

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 nev开发者_运维技巧ertheless 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.


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]


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]
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号