SoFunction
Updated on 2025-03-03

Use python itertools to calculate the orders for full reduction in Double Eleven

Double Eleven

Order problem

The annual Double Eleven is here again. On such a day, you may encounter some problems, first of all, the problem of "summarizing orders". For example, in e-commerce activities, there is often a "full reduction", for example, "over 200, 30 reduction". In this case, we need to achieve the goal or exceed the goal (because, if the goal is not reached, we cannot make a full reduction).

Obviously, if we buy items worth 200 yuan, we will pay 170 yuan (equivalent to 85% off), while if we buy items worth 300 yuan, we will pay 270 yuan (equivalent to 10% off). That is, we need to find one or more product combinations so that the sum of their prices is as close to the target amount as possible and exceed the target amount.

Points Questions

Another common problem is the "point redemption" problem. For example, if there are 1,000 points in the account, you can redeemed several things. In this case, we need to be as close to the target as possible, but we cannot exceed the target (because, the behavior of exceeding the points is not allowed).

Obviously, points usually have a deadline, and the remaining points often do not play any role. That is, we need to find one or more product combinations so that the sum of their prices is as close to the target points as possible, but not exceed the target points.

Problem solving

Solve the issue of order-making

Solution:

1. If a product list price, target amount, and define a variable min_excess, to record the smallest value exceeding the amount, best_combination is used to store the optimal combination.

2. Select each item from prices, calculate the total price of the product combination, and if the price exceeds the target, check whether it is the current closest combination. If the total price does not exceed the target, continue to add other items.

3. Finally, the optimal combination best_combination is obtained.

from itertools import combinations
 
def find_best_combination(prices, target):
    best_combination = None
    min_excess = float("inf")
    
    for i in range(1, len(prices) + 1):
        for comb in combinations(prices, i):
            total_price = sum(comb)
            
            if total_price >= target and (total_price - target) < min_excess:
                min_excess = total_price - target
                best_combination = comb
                
    return best_combination, sum(best_combination) if best_combination else 0
 
 
prices = [66, 33, 24, 89, 77]
target = 200
 
best_combination, best_price = find_best_combination(prices, target)
print(f"Optimal combination: {best_combination}, Total price: {best_price}")

Here, we use a tool, combinations in the itertools library, which function is to generate non-repetitive combinations of elements.

# Take [1, 2, 3] as an example 
# The result at this time is: [(1,), (2,), (3,)]print(list(combinations([1, 2, 3], 1)))
 
# The result at this time is: [(1, 2), (1, 3), (2, 3)]print(list(combinations([1, 2, 3], 2)))
 
# The result at this time is: [(1, 2, 3)]print(list(combinations([1, 2, 3], 3)))

Solve points redemption

Similar to the issue of order-making, it only needs to not exceed the closest value.

from itertools import combinations
 
def find_best_combination(prices, target):
    best_combination = None
    max_total = 0
    
    for i in range(1, len(prices) + 1):
        for comb in combinations(prices, i):
            total_price = sum(comb)
            
            if total_price <= target and total_price > max_total:
                max_total = total_price
                best_combination = comb
                
    return best_combination, max_total
 
 
prices = [66, 33, 24, 89, 77]
target = 200
 
best_combination, best_price = find_best_combination(prices, target)
print(f"Optimal combination: {best_combination}, Total points: {best_price}")

Save multiple results

Sometimes, although we get the best results, the best results are not necessarily what we hope for. For example, among the best results, the product you buy may not be the one we are most satisfied with, so saving multiple combination solutions can provide multiple references.

For the order-making problem:

from itertools import combinations
import heapq
 
def find_top_combinations(prices, target, top_n=5):
    heap = []
    for i in range(1, len(prices) + 1):
        for comb in combinations(prices, i):
            total_price = sum(comb)
            if total_price >= target:
                excess = total_price - target
                (heap, (-excess, total_price, comb))
                if len(heap) > top_n:
                    (heap)
 
    top_combinations = sorted(heap, key=lambda x: -x[0])
    return [(comb[2], comb[1]) for comb in top_combinations]
 
prices = [66, 33, 24, 89, 77]
target = 200
top_n = 5
 
top_combinations = find_top_combinations(prices, target, top_n=top_n)
print(f"The best{top_n}Combinations and their total price:")
for i, (combination, total_price) in enumerate(top_combinations, 1):
    print(f"combination {i}: {combination}, Total price: {total_price}")

At this time, you can see the result as:

The best 5 combinations and their total price:
Combination 1: (66, 33, 24, 77), Total price: 200
Combination 2: (66, 33, 24, 89), Total price: 212
Combination 3: (33, 24, 89, 77), Total price: 223
Combination 4: (66, 89, 77), Total price: 232
Combination 5: (66, 24, 89, 77), Total price: 256

Regarding points redemption questions:

from itertools import combinations
import heapq
 
def find_top_combinations(prices, target, top_n=5):
    top_combinations = []
 
    for i in range(1, len(prices) + 1):
        for comb in combinations(prices, i):
            total_price = sum(comb)
 
            if total_price <= target:
                if len(top_combinations) < top_n:
                    (top_combinations, (total_price, comb))
                else:
                    if total_price > top_combinations[0][0]:
                        (top_combinations, (total_price, comb))
 
    top_combinations.sort(reverse=True, key=lambda x: x[0])
    return [(comb[1], comb[0]) for comb in top_combinations]
 
prices = [66, 33, 24, 89, 77]
target = 200
top_n = 5
 
top_combinations = find_top_combinations(prices, target, top_n=top_n)
print(f"The best{top_n}Combinations and their total price:")
for i, (combination, total_price) in enumerate(top_combinations, 1):
    print(f"combination {i}: {combination}, Total price: {total_price}")

You can see the results as:

The best 5 combinations and their total price:
Combination 1: (66, 33, 24, 77), Total price: 200
Combination 2: (33, 89, 77), Total price: 199
Combination 3: (24, 89, 77), Total price: 190
Combination 4: (66, 33, 89), Total price: 188
Combination 5: (66, 24, 89), Total price: 179

This is the article about using python itertools to calculate the orders for full reduction in Double Eleven. For more related content on python calculation, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!