gpt-4o继续迭代考场安排程序 一键生成考场清单

        接上两篇gpt-4o考场安排-CSDN博客,考场分层次安排,最终exe版-CSDN博客

当然你也可以只看这一篇。

今天又添加了以下功能,程序见后。

1、自动分页,每个考场打印一页

2、添加了打印试场单页眉

3、添加了页脚 第X页,其X页, 打印时间

表结构

程序运行界面

测试分配考场环境,共15个班分为两个层次由字段“层次”指定a, b。a层次9个考场,b层次15个,从b层开始编号,a层次考场号从16开编。

预览结果b层次

层次a预览结果

完整程序


import sys

import pandas as pd

import random

import openpyxl

from openpyxl.worksheet.pagebreak import Break

from openpyxl.styles import Font, Alignment, PatternFill, Border, Side

from openpyxl.worksheet.page import PageMargins

from datetime import datetime

from PyQt5.QtWidgets import (

    QApplication, QLabel, QLineEdit, QPushButton, QFileDialog,

    QVBoxLayout, QWidget, QMessageBox

)

from PyQt5.QtGui import QFont as QPyQtFont


def load_data(filename):
    return pd.read_excel(filename)


def save_data(df, filename, exam_name):
    df.to_excel(filename, index=False)

    format_excel(filename, df, exam_name)


def assign_seats(df, total_halls, start_hall=1):
    grouped = df.groupby('班级')

    groups = [group.sample(frac=1).reset_index(drop=True) for _, group in grouped]

    groups.sort(key=lambda x: len(x), reverse=True)

    iterators = [iter(group.iterrows()) for group in groups]

    arranged_data = []

    hall_number = start_hall

    seat_number = 1

    total_students = len(df)

    students_per_hall = total_students // total_halls

    extra_students = total_students % total_halls

    while iterators:

        random.shuffle(iterators)

        for it in iterators[:]:

            try:

                _, student = next(it)

                student_data = student.to_dict()

                student_data["考场"] = hall_number

                student_data["考号"] = f"{seat_number:02d}"

                arranged_data.append(student_data)

                seat_number += 1

                if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):
                    hall_number += 1

                    seat_number = 1

                if hall_number >= start_hall + total_halls:
                    hall_number = start_hall

            except StopIteration:

                iterators.remove(it)

    return arranged_data


def check_and_adjust_seating(arranged_data):
    def has_adjacent_same_class(data):

        for i in range(len(data) - 1):

            if data[i]['班级'] == data[i + 1]['班级']:
                return i

        return -1

    def find_valid_swap(index, data):

        current_class = data[index]['班级']

        for j in range(len(data)):

            if j != index and data[j]['班级'] != current_class:

                if (j == 0 or data[j - 1]['班级'] != current_class) and (

                        j == len(data) - 1 or data[j + 1]['班级'] != current_class):
                    return j

        return -1

    swap_operations = []

    while True:

        index = has_adjacent_same_class(arranged_data)

        if index == -1:
            break

        swap_index = find_valid_swap(index + 1, arranged_data)

        if swap_index == -1:
            raise ValueError("Cannot find a valid swap to adjust the seating arrangement.")

        swap_operations.append((index + 1, swap_index))

        arranged_data[index + 1], arranged_data[swap_index] = arranged_data[swap_index], arranged_data[index + 1]

    return arranged_data, swap_operations


def reassign_seats(arranged_data, total_halls, start_hall=1):
    hall_number = start_hall

    seat_number = 1

    total_students = len(arranged_data)

    students_per_hall = total_students // total_halls

    extra_students = total_students % total_halls

    for i, student in enumerate(arranged_data):

        student['考场'] = hall_number

        student['考号'] = f"{seat_number:02d}"

        seat_number += 1

        if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):
            hall_number += 1

            seat_number = 1

        if hall_number >= start_hall + total_halls:
            hall_number = start_hall

    return arranged_data


def format_excel(filename, df, exam_name):

    if '层次' in df.columns:

        df = df.drop(columns=['层次'])



    wb = openpyxl.Workbook()

    ws = wb.active

    ws.title = "考场安排结果"



    # 将标题从第一行开始写入

    for col_num, column_title in enumerate(df.columns, 1):

        cell = ws.cell(row=1, column=col_num, value=column_title)

        cell.font = Font(bold=True, color="FFFFFF", size=16)

        cell.fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")

        cell.alignment = Alignment(horizontal="center", vertical="center")



    for row_num, row_data in enumerate(df.itertuples(index=False, name=None), 2):

        for col_num, cell_value in enumerate(row_data, 1):

            ws.cell(row=row_num, column=col_num, value=cell_value)



    for col in ws.columns:

        max_length = 0

        column = col[0].column_letter

        # Check if the column header is "考号"

        if ws.cell(row=1, column=col[0].col_idx).value == "考号":

            adjusted_width = 20  # 设置考号列的宽度为20

        else:

            for cell in col:

                if cell.value is not None:

                    max_length = max(max_length, len(str(cell.value)))

            adjusted_width = max_length + 10

        ws.column_dimensions[column].width = adjusted_width



    # 调整页面边距

    ws.page_margins = PageMargins(left=1.5, right=0.75, top=1.2, bottom=0.5)



    ws.print_title_rows = '1:1'  # 标题行在第一行开始

    ws.page_setup.orientation = 'portrait'

    ws.page_setup.paperSize = ws.PAPERSIZE_A4

    ws.page_setup.fitToPage = True

    ws.page_setup.fitToWidth = 1

    ws.page_setup.fitToHeight = False

    ws.page_setup.horizontalCentered = True

    ws.page_setup.verticalCentered = True



    page_height_in_inches = 11.69 - ws.page_margins.top - ws.page_margins.bottom

    page_height_in_points = page_height_in_inches * 72

    header_height_in_points = 50

    available_row_height_in_points = page_height_in_points - header_height_in_points



    hall_groups = df.groupby('考场')

    previous_max_row = 1  # 前一个最大行号调整为1以考虑空行

    thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin'))

    for hall_number, (hall_id, hall_df) in enumerate(hall_groups):

        row_count = len(hall_df) + 1

        max_row = hall_df.index[-1] + 2  # 从第二行开始每个考场的数据

        row_height = available_row_height_in_points / row_count

        row_height = max(row_height, 15)

        for row in range(previous_max_row, max_row + 1):

            ws.row_dimensions[row].height = row_height

            for cell in ws[row]:

                cell.border = thin_border

                cell.font = Font(size=15)

                cell.alignment = Alignment(horizontal="center", vertical="center")

        if max_row < ws.max_row:

            ws.row_breaks.append(Break(max_row))

        previous_max_row = max_row + 1



    # 添加页眉和页脚,并使用制表符来向左移动页眉

    ws.oddHeader.center.text = f"&\"微软雅黑,Bold\"&20\t{exam_name}"  # 添加制表符以向左移动

    ws.oddFooter.center.text = "第 &P 页,共 &N 页"

    ws.oddFooter.right.text = f"&D &T"



    wb.save(filename)


def dataframe_to_rows(df, index=True, header=True):
    if header:

        rows = [list(df.columns)]

    else:

        rows = [[]]

    for row in df.itertuples(index=index, name=None):
        rows.append(list(row)[1:])

    return rows


def run_allocation(input_filename, a_total_halls, b_total_halls, start_level, exam_name):
    df = load_data(input_filename)

    if start_level == 'b':

        other_level = 'a'

        first_total_halls = b_total_halls

        second_total_halls = a_total_halls

    else:

        other_level = 'b'

        first_total_halls = a_total_halls

        second_total_halls = b_total_halls

    first_level_students = df[df['层次'] == start_level]

    arranged_first_students = assign_seats(first_level_students, first_total_halls, start_hall=1)

    adjusted_first_students, _ = check_and_adjust_seating(arranged_first_students)

    final_first_students = reassign_seats(adjusted_first_students, first_total_halls, start_hall=1)

    second_level_students = df[df['层次'] == other_level]

    arranged_second_students = assign_seats(second_level_students, second_total_halls, start_hall=first_total_halls + 1)

    adjusted_second_students, _ = check_and_adjust_seating(arranged_second_students)

    final_second_students = reassign_seats(adjusted_second_students, second_total_halls,
                                           start_hall=first_total_halls + 1)

    combined_students = final_first_students + final_second_students

    arranged_df = pd.DataFrame(combined_students)

    current_time = datetime.now().strftime("%Y%m%d_%H%M%S")

    output_filename = f"考场安排结果_{current_time}.xlsx"

    save_data(arranged_df, output_filename, exam_name)

    return output_filename


class ExamArrangementApp(QWidget):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        layout = QVBoxLayout()

        font = QPyQtFont("Arial", 14)

        self.file_label = QLabel('选择文件:')

        self.file_label.setFont(font)

        layout.addWidget(self.file_label)

        self.file_btn = QPushButton('选择文件')

        self.file_btn.setFont(font)

        self.file_btn.clicked.connect(self.select_file)

        layout.addWidget(self.file_btn)

        self.exam_name_label = QLabel('考试名称:')

        self.exam_name_label.setFont(font)

        layout.addWidget(self.exam_name_label)

        self.exam_name_input = QLineEdit()

        self.exam_name_input.setFont(font)

        layout.addWidget(self.exam_name_input)

        self.a_halls_label = QLabel('A层次考场数:')

        self.a_halls_label.setFont(font)

        layout.addWidget(self.a_halls_label)

        self.a_halls_input = QLineEdit()

        self.a_halls_input.setFont(font)

        layout.addWidget(self.a_halls_input)

        self.b_halls_label = QLabel('B层次考场数:')

        self.b_halls_label.setFont(font)

        layout.addWidget(self.b_halls_label)

        self.b_halls_input = QLineEdit()

        self.b_halls_input.setFont(font)

        layout.addWidget(self.b_halls_input)

        self.start_level_label = QLabel('首先开始编号的层次 (a/b):')

        self.start_level_label.setFont(font)

        layout.addWidget(self.start_level_label)

        self.start_level_input = QLineEdit()

        self.start_level_input.setFont(font)

        layout.addWidget(self.start_level_input)

        self.run_btn = QPushButton('运行')

        self.run_btn.setFont(font)

        self.run_btn.clicked.connect(self.run)

        layout.addWidget(self.run_btn)

        self.setLayout(layout)

        self.setWindowTitle('考场安排工具,By Bobo googaobo@gmail.com')

        self.resize(900, 630)

        self.center()

    def select_file(self):

        options = QFileDialog.Options()

        options |= QFileDialog.DontUseNativeDialog

        file_name, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xlsx);;All Files (*)",
                                                   options=options)

        if file_name:
            self.file_label.setText(f'文件: {file_name}')

            self.input_filename = file_name

    def run(self):

        try:

            a_total_halls = int(self.a_halls_input.text())

            b_total_halls = int(self.b_halls_input.text())

            start_level = self.start_level_input.text()

            exam_name = self.exam_name_input.text()

            output_filename = run_allocation(self.input_filename, a_total_halls, b_total_halls, start_level, exam_name)

            QMessageBox.information(self, "成功", f"已成功生成文件:{output_filename}", QMessageBox.Ok)

        except Exception as e:

            QMessageBox.critical(self, "错误", str(e), QMessageBox.Ok)

    def center(self):

        qr = self.frameGeometry()

        cp = self.screen().availableGeometry().center()

        qr.moveCenter(cp)

        self.move(qr.topLeft())


if __name__ == '__main__':
    app = QApplication(sys.argv)

    ex = ExamArrangementApp()

    ex.show()

    sys.exit(app.exec_())

程序已打包exe,点赞留言QQ,发送程序。程序运行中有问题请评论区留言交流!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/652093.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot项目——网页版本五子棋

网页五子棋&#xff1a;本项目简单实现了网页版本的五子棋对战功能&#xff0c;同时会根据用户的天梯分数来匹配&#xff0c;可供多位用户同时提供对战功能。大致可分为三个模块&#xff0c;用户模块&#xff0c;匹配模块&#xff0c;对战模块&#xff0c;下面重点介绍以下三个…

班翠鸟优化算法(PKO)-2024年SCI新算法-公式原理详解与性能测评 Matlab代码免费获取

​ 声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 一、初始化阶段 二、栖…

C# 字节数组(byte[])拼接的性能对比测试

将C#中的三种字节数组拼接方式的性能做了一个对比测试&#xff0c;DEMO程序代码如下&#xff1a; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Byte数组拼接测…

typora自动生成标题序号(修改V1.0)

目录 带序号效果图 解决方法 带序号效果图 解决方法 1.进入文件夹&#xff1a;文件–>偏好设置–>外观–>主题–>打开主题文件夹 2.如果没有base.user.css文件&#xff0c;新建一个。如果有直接用记事本打开&#xff0c;把下面代码拷贝进去保存。 /** initiali…

免税商品优选购物商城,基于 SpringBoot+Vue+MySQL 开发的前后端分离的免税商品优选购物商城设计实现

目录 一. 前言 二. 功能模块 2.1. 登录界面 2.2. 管理员功能模块 2.3. 商家功能模块 2.4. 用户前台功能模块 2.5. 用户后台功能模块 三. 部分代码实现 四. 源码下载 一. 前言 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过…

前端开发之xlsx-js-style的使用和实例

xlsx-js-style的使用和实例 前言效果图安装xlsx-js-style插件导入插件在创建ws后设置表头 前言 在使用xlsx组件的时候如果需要调整xlsx表的样式可以使用xlsx-js-style来进行设置 效果图 安装xlsx-js-style插件 npm install xlsx-js-style导入插件 该文件参考在xlsx的使用中…

各种情况下的线缆大小选择

开口线鼻子和导线对应大小 开口铜鼻子对应线径大小 变压器容量对应高压侧电流大小 开关电流线缆功率对照表 家庭/工业最常用电线铜线电流承载功率 电工常用名词对应符号 导线面积承载的安全载流量及允许负荷对照表 漏电保护器选择参考表 电动机功率换算电流 电机功…

数据(整型和浮点数)在内存中的存储

目录 1.整型在内存中的存储 大小端字节序存储和字节序判断 1.大小端字节序存储&#xff1a; 2.字节序判断&#xff1a; 2.浮点数在内存中的存储 浮点数存储的过程 浮点数读取的过程 题目解析 1.整型在内存中的存储 我们先要明白&#xff1a; 整数在内存中是以二进制形式…

数据结构(六)队列

文章目录 一、概念二、逻辑结构&#xff1a;线性结构三、存储结构&#xff08;一&#xff09;顺序队列&#xff08;二&#xff09;循环队列1. 结构体定义2. 创建队列&#xff08;1&#xff09;函数定义&#xff08;2&#xff09;注意点&#xff08;3&#xff09;代码实现 3. 入…

SQLI-labs-第二十五关和第二十五a关

目录 第二十五关 1、判断注入点 2、判断数据库 3、判断表名 4、判断字段名 5、获取数据库的数据 第二十五a关 1、判断注入点 2、判断数据库 第二十五关 知识点&#xff1a;绕过and、or过滤 思路&#xff1a; 通过分析源码和页面&#xff0c;我们可以知道对and和or 进…

解决 WooCommerce 的分析报表失效问题

今天明月的一个境外电商客户反应网站的 WooCommerce 分析报表已经十多天没有更新了&#xff0c;明明每天都有订单交易可分析报表里的数据依旧是十多天前的&#xff0c;好像更新完全停滞了似的。明月也及时的查看了后台的所有设置&#xff0c;确认没有任何问题&#xff0c;WooCo…

什么是光栅化?

一、 什么是光栅化? 光栅化作用是将几何数据变换后转换为像素呈现在显示设备上的一个过程。几何数据转换为像素&#xff0c; 本质是坐标变换、几何离散化&#xff0c;如下&#xff1a; 其中包含了坐标变换和几何离散化&#xff1a; 二、光栅化完成了什么 3D中&#xff0c;物…

数组-两个升序数组中位数

一、题目描述 二、解题思路 (一).基本思想&#xff1a; 如果列表总长度allsize( arr1.size()arr2.size() ) 为奇数时&#xff0c;中位数位置应该在两个列表排序后的第 allsize/2 位置处&#xff0c;如果allsize为偶数&#xff0c;中位数应该取 (allsize/2)-1 和 allsize/2 的…

Google Extension 【Google 最佳扩展插件】

pockettube: youtube manager 订阅号分组沉浸式翻译&#xff1a;全网口碑炸裂的双语对照网页翻译插件Google 翻译腾讯翻译篡改猴MetaMaskGlarity: Summarize & Translate Any Page

移动端应用订阅SDK接入攻略

本文档介绍了联想应用联运移动端订阅SDK接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运移动端订阅SDK。 接入前准备 1请先与联想商务达成合作意向。 2.联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#…

卸载/删除 Maxask.com,最简单的方法

被绑架的浏览器&#xff0c;太恶心了。 Maxask伪装成了插件&#xff0c;在你搜索网页的时候利用了重定向&#xff0c;导致出现的界面时Maxask的界面&#xff0c;很恶心。 只需要排查正在使用的&#xff0c;如下图有颜色的图表。 删除一个插件&#xff0c;浏览器搜索一下看看有…

2024年上半年软件设计师试题及答案(回忆版)--选择题

基础知识选择题 基础知识选择题 1,2,3][4,5,6][1,2,3,4,5,6] &#xff08;总&#xff1a;1分&#xff09; &#xff08;注意&#xff1a;括号内的是截止当前题目总分&#xff09; vlan不能隔绝内外网 &#xff08;2分&#xff09; 链路层使用交换机&#xff0c;…

C语言 | Leetcode C语言题解之第115题不同的子序列

题目&#xff1a; 题解&#xff1a; int numDistinct(char* s, char* t) {int m strlen(s), n strlen(t);if (m < n) {return 0;}unsigned long long dp[m 1][n 1];memset(dp, 0, sizeof(dp));for (int i 0; i < m; i) {dp[i][n] 1;}for (int i m - 1; i > 0;…

M2m中的采样

采样的完整代码 import torch import numpy as np from torchvision import datasets, transforms from torch.utils.data import DataLoader, WeightedRandomSampler, SubsetRandomSamplerdef get_oversampled_data(dataset, num_sample_per_class):""" Gener…

Brewer Science将在CS Mantech进行展示

在风景如画的亚利桑那州图森市举办的CS Mantech盛会上&#xff08;2024年5月20日至23日&#xff09;&#xff0c;杰出化合物半导体材料企业Brewer Science&#xff0c;将带来一场名为“化合物半导体制造的创新材料解决方案”的演讲盛宴。这一演讲&#xff0c;定于五月二十一日星…