python接单记录:我用tk写了一个求从50个数中选20个数的组合数的程序

本文记录了一次使用Python完成的接单任务,该任务要求创建一个前端界面,用户输入50以内的数字和选择数(20以内),程序计算并显示所有可能的组合。主要使用tkinter构建界面,itertools.combinations计算组合数,openpyxl导出到Excel。程序通过迭代器避免了大量内存占用,每次点击显示1000个结果,直到所有组合显示完毕。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

小伙伴们大家好!这篇文章记录了我接单写的一个程序,客户要求输入50(以内)个数,输入选取数(20以内),显示他们的排列组合,并且要有一个前端界面。看到这个需求的时候我也没多想,觉得很简单,就接了,写这个程序大概用了3个多小时。当我写完看测试结果的时候,我一度以为被客户耍了,因为如果是50选20的话,这个结果数太大了,一天一夜也算不出来呀。好在最后成果交易,客户肯定是学生,大概是老师出的题目吧(不太明白老师为啥出这种题目)。

一、知识点

我的程序主要用到了三个模块:tkinter(写前端界面),combinations(求组合数),openpyxl(将结果导出到excel)

二、前端编写

通常情况我都是先写程序的核心代码,即先实现功能,再写界面,但是因为实现组合数的功能,可以使用itertools模块中的combinnations轻松实现,所以我先写了前端部分。
按照客户的需求,制定了下面的界面,代码也没什么好多说的。

在这里插入图片描述
用户可以输入最多50个数字,选取数最大为20,点击显示结果,出现组合总数、计算时间、还有所有的组合列表,每次显示1000个,再点击显示结果再出现1000个。如果输入的数字或者选取数发生变化的话,点击显示结果就会重新计算组合。点击导出文件会将显示的结果导出到excel文件里。
对于每次点击显示结果会刷新1000个结果这个功能,我定义了一个变量button_num,初始值为0,每点击一次+1,每次点击按钮的时候都判断一下button_num的值,如果等于0就重新计算排列组合,如果大于0就刷新结果,当结果显示完button_num值再赋0。

三、排列组合功能的实现

排列组合我们首先会想到用递归函数去写,但怎么去写呢,递归真的是会者不难,难者不会呀,好在Python具有强大的库,可以轻松帮我们实现。

from itertools import combinations    
result = combinations(list[], m))    #list[]为输入的数字列表,m为选取数
for i in result:
	print(i)

我没有少写,四行代码就实现了排列组合。首先导入combinations模块,传入输入的50个数字列表和选取数,然后就输出结果了。是不是超级简单,Python真的是yyds。
因为组合数太多了,用列表存放的话会大量占用内存,所以使用了迭代器。

组合数 = sum(1 for _ in combinations(n, m))
所有的排列组合 = iter(i for i in combinations(n, m))

对于combinnations的使用我也是第一次,不太确定他是不是迭代器,只知道迭代一次之后值就消失了,知道的小伙伴可以留言告诉我。在实际的代码中,我调用了两次combinations,第一次是为了计算组合数,第二次是将排列组合结果存放到迭代器中,这是因为我没有找到combinations类似于next()的用法,所以只能把结果放入iter定义的迭代器中,以便后续显示结果。

四、将结果导出到excel
import openpyxl

wb = openpyxl.Workbook()
ws = wb.active
for each in result:
    ws.append(each)
wb.save(filename)

操作excel学会两个模块就可以了,一个是pandas,另一个就是openpyxl,这两个模块是互补的,想详细学习的小伙伴可以自行去学习。

五、总结

总体来说这个程序是比较简单的,我挣得也不多,但是作为python的初学者,每一次接单都是对我学习的激励。我也会慢慢在csdn上把我接单的程序发布,既是作为我自己的总结,也是为了能和其他的伙伴进行交流。下面把程序的源码附上。

from itertools import combinations
import re
from tkinter import *
from tkinter import messagebox
import time
import threading
from tkinter.scrolledtext import ScrolledText
import openpyxl


class Application(Frame):
    def __init__(self, master):
        super().__init__(master)
        self.numbers = StringVar()  
        self.max_num = IntVar()  
        self.input_n = ''    
        self.input_m = 0    
        self.sums = IntVar()    
        self.times = StringVar()   
        self.text = Text()    
        self.result = iter(range(2))   
        self.button_num = 0    
        self.show_list = []    
        self.num = []   
        self.create_widget()   

    def create_widget(self):
        Label(self.master, text='请输入数字:').place(x=10, y=20)
        Entry(self.master, textvariable=self.numbers, width=40).place(x=92, y=20)
        Label(self.master, text='选取:').place(x=455, y=20)
        Entry(self.master, textvariable=self.max_num, width=4).place(x=495, y=20)
        Label(self.master, text='的所有组合').place(x=520, y=20)
        Label(self.master, text='组合总数:').place(x=605, y=20)
        Label(self.master, textvariable=self.sums).place(x=680, y=20)
        Button(self.master, text='显示结果', width=8, height=1, command=lambda: th(self.main)).place(x=760, y=15)
        Button(self.master, text='导出文件', width=8, height=1, command=lambda: th(self.save)).place(x=760, y=50)
        Label(self.master, text='显示所有组合列表').place(x=10, y=55)
        Label(self.master, text='计算时间:').place(x=350, y=55)
        Label(self.master, textvariable=self.times).place(x=460, y=55)
        self.text = ScrolledText(self.master, width=90, height=18)
        self.text.place(x=10, y=90)

    def main(self):
        start_time = time.time()
        if self.input_n != self.numbers.get() or self.input_m != self.max_num.get():
            self.button_num = 0
        if self.button_num > 0:
            self.show()
            self.button_num += 1
            return
        n = []
        self.input_n = self.numbers.get()
        self.input_m = self.max_num.get()
        n_list = re.findall(r'\d+', self.input_n)
        if len(n_list) == 0:
            messagebox.showinfo(title='提示', message=f'输入为空')
            return
        if self.input_m > len(n_list):
            messagebox.showinfo(title='提示', message=f'输入的选取数大于输入的数字总数')
            return
        if self.input_m > 20:
            messagebox.showinfo(title='提示', message=f'选取数不能大于20')
            return
        if len(n_list) > 50:
            messagebox.showinfo(title='提示', message=f'输入的数字总数不能大于50个')
            return
        for i in n_list:
            n.append(int(i))
        self.text.delete('1.0', END)
        self.text.insert(END, '计算中...')
        self.sums.set(sum(1 for _ in combinations(n, self.input_m)))
        self.result = iter(i for i in combinations(n, self.input_m))
        end_time = time.time()
        self.times.set(str(end_time - start_time))
        self.show()
        self.button_num += 1
        return

    def show(self):
        self.text.delete('1.0', END)
        self.show_list = []
        self.num = []
        for i in range(1000):
            try:
                self.show_list.append(self.result.__next__())
                self.num.append(self.button_num * 1000 + i + 1)
                self.text.insert(END, f'{self.num[-1]}    {self.show_list[-1]}\n')
            except StopIteration:
                self.text.insert(END, '结果显示完毕')
                self.button_num = -1
                return
        return

    def save(self):
        if not self.show_list:
            messagebox.showinfo(title='提示', message=f'结果为空')
            return
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.append(['序号', '结果'])
        n = 0
        for each in self.show_list:
            ws.append([self.num[n], str(each)])
            n = n + 1
        filename = '导出结果(' + str(self.num[0]) + '-' + str(self.num[-1]) + ').xlsx'
        wb.save(filename)
        messagebox.showinfo(title='提示', message=f'导出成功')


def th(func, *args):
    t = threading.Thread(target=func, args=args)
    t.setDaemon(True)
    t.start()


if __name__ == '__main__':
    root = Tk()
    root.title('N选M个数组合')
    root.geometry('850x410+200+50')
    app = Application(root)
    root.mainloop()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值