吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1913|回复: 8
收起左侧

[Python 原创] 闲来无事,写个给表格分组或合并的小工具

  [复制链接]
tkdahai 发表于 2023-5-17 20:20
玩python 时间也不长,有时办公要用到EXCEL里不断重复的分组,合并数据,ctrl+v,ctrl+c ,搞的手指发麻,于是就抽空搞了这么个小工具,用的是pandas,网上,同时也借用了一些大佬的作品,揉合而成。放在这与大家共勉,一起学习,bug不断,欢迎留下脚印。
[Python] 纯文本查看 复制代码
      
from PyQt5.QtNetwork import QLocalSocket, QLocalServer  # 实例化程式,只许一个运行
from PyQt5 import QtCore
from PyQt5.QtGui import QTextCursor, QColor
from PyQt5.QtWidgets import *
#from PyQt5.QtWidgets import QApplication, QFileDialog
import sys,os
import pandas as pd
from PyQt5.QtWidgets import QApplication, QComboBox, QDialog, QVBoxLayout, QLabel, QPushButton,QFileDialog
from win32com.client import Dispatch
import openpyxl
class ComboCheckBox(QComboBox):
    def __init__(self, items: list):
         """
         initial function
         :param items: the items of the list
         """
         super(ComboCheckBox, self).__init__()
         self.items = ["全选"] + items  # items list
         self.box_list = []  # selected items
         self.text = QLineEdit()  # use to selected items
         self.state = 0  # use to record state

         q = QListWidget()
         for i in range(len(self.items)):
             self.box_list.append(QCheckBox())
             self.box_list[i].setText(self.items[i])
             item = QListWidgetItem(q)
             q.setItemWidget(item, self.box_list[i])
             if i == 0:
                 self.box_list[i].stateChanged.connect(self.all_selected)
             else:
                 self.box_list[i].stateChanged.connect(self.show_selected)

         q.setStyleSheet("font-size: 30px; font-weight: bold; height: 50px; margin-left: 15px")
         #self.setStyleSheet("width: 300px; height: 50px; font-size: 21px; font-weight: bold")
         self.text.setReadOnly(True)
         self.setLineEdit(self.text)
         self.setModel(q.model())
         self.setView(q)

    def all_selected(self):
         """
         decide whether to check all
         :return:
         """
         # change state
         if self.state == 0:
             self.state = 1
             for i in range(1, len(self.items)):
                 self.box_list[i].setChecked(True)
         else:
             self.state = 0
             for i in range(1, len(self.items)):
                 self.box_list[i].setChecked(False)
         self.show_selected()

    def get_selected(self) -> list:
         """
         get selected items
         :return:
         """
         ret = []
         for i in range(1, len(self.items)):
             if self.box_list[i].isChecked():
                 ret.append(self.box_list[i].text())
         return ret

    def show_selected(self):
         """
         show selected items
         :return:
         """
         self.text.clear()
         ret = '; '.join(self.get_selected())
         self.text.setText(ret)
class MyDialog(QDialog):
    def __init__(self):
        #定义列名列表大A-Z
        col_list = list(map(chr, range(65, 91)))
        self.file_name = ''
        self.output = 'output.xlsx'  # 输出OUT表


        #self.win__dir = os.environ['HOMEPATH'] + '//' + 'Desktop'  # 打开文件默认活动桌面
       # RC = read.read_config(self=read)  # 传总参,导入配置文件,为后面的参数做基础
        # 传参,导入压缩图片类和其参数(参数读取自配置文件)
        # self.Result = result.Compress_img(RC.get('api', 'rate'), RC.get('api', 'quality'), RC.get('api', 'way'))
        # self.url = RC.get('api', 'url')  #从配置文件提参数get示例
        ####sytext水印文字
        # sytext = RC.get('sylogo','sytime')+'\n'+RC.get('sylogo', 'syadd')+'\n'+RC.get('sylogo', 'syen')
        super().__init__()
        """控件的创建和布局"""
        ########1。先创建按键筐
        #self.lineEdit = QLineEdit("")  # 路经显示
        self.textEdit = QTextEdit()  # 富文本显示
        ###################################
        self.pushExcel = QLabel("Excel表:")
        #self.pushExcel.setMinimumWidth(100)
        self.lineExcel = QLineEdit("")  # 路经显示
        #self.lineExcel.setMinimumWidth(100)
        self.selExcel = QPushButton("请选择")
        #self.selExcel.setMinimumWidth(100)
        ################################
        self.pushGroup = QLabel("分组列: ")
        #self.pushGroup.setMinimumWidth(50)
        #self.listGroup = QLineEdit("")  # 路经显示
        self.listGroup = ComboCheckBox(col_list)
       # self.listGroup.setMinimumWidth(300)
        ########################
        self.pushMerge = QLabel("合并列: ")
        #self.pushMerge.setMinimumWidth(50)
        #self.listMerge = QLineEdit("")  # 路经显示
        self.listMerge = ComboCheckBox(col_list)
        #self.listMerge.setMinimumWidth(50)
        #########################
        self.pushGO = QPushButton("开始处理")
        #self.pushGO.setMinimumWidth(50)
        self.pushSee = QPushButton("结果查询")
        #self.pushSee.setMinimumWidth(50)

        ######################2.创建第一排水平表单布局
        self.hflo0 = QFormLayout()  # 创建水平表单布局
        self.hflo1 = QFormLayout()  # 创建水平表单布局
        self.hflo2 = QFormLayout()  # 创建水平表单布局

        ######################2.1创建第二排水平表单布局
        self.hflo11 = QFormLayout()  # 创建水平表单布局
        self.hflo12 = QFormLayout()  # 创建水平表单布局
        ######################2.1创建第三排水平表单布局
        self.hflo21 = QFormLayout()  # 创建水平表单布局
        self.hflo22 = QFormLayout()  # 创建水平表单布局
        ######################2.1创建第四排水平表单布局
        self.hflo31 = QFormLayout()  # 创建水平表单布局
        self.hflo32 = QFormLayout()  # 创建水平表单布局
        ###############3.将第一排水平表单和按键结合
        self.hflo0.addRow(self.pushExcel)
        self.hflo1.addRow(self.lineExcel)
        self.hflo2.addRow(self.selExcel)

        ###############3.1将第二排水平表单和按键结合
        self.hflo11.addRow(self.pushGroup)
        self.hflo12.addRow(self.listGroup)
        ###############3.1将第三排水平表单和按键结合
        self.hflo21.addRow(self.pushMerge)
        self.hflo22.addRow(self.listMerge)
        ###############3.1将第4排水平表单和按键结合
        self.hflo31.addRow(self.pushGO)
        self.hflo32.addRow(self.pushSee)
        ################4.创建垂直表单布局 路经显示和富文本
        self.vflo = QFormLayout()  # 创建垂直表单布局 路经显示和富文本
        #self.vflo.addRow(self.lineEdit)
        self.vflo.addRow(self.textEdit)
        ################5. 添加水平布局第一排(也可以再加一排)
        self.hbox = QHBoxLayout()
        self.hbox.addLayout(self.hflo0)
        self.hbox.addLayout(self.hflo1)
        self.hbox.addLayout(self.hflo2)
        self.hbox.setSpacing(0)
        ################5.1 添加水平布局第二排(也可以再加一排)
        self.hbox2 = QHBoxLayout()
        self.hbox2.addLayout(self.hflo11)
        self.hbox2.addLayout(self.hflo12)
        self.hbox2.setSpacing(0)
        ################5.1 添加水平布局第三排(也可以再加一排)
        self.hbox3 = QHBoxLayout()
        self.hbox3.addLayout(self.hflo21)
        self.hbox3.addLayout(self.hflo22)
        self.hbox3.setSpacing(0)
        ################5.1 添加水平布局第4排(也可以再加一排)
        self.hbox4 = QHBoxLayout()
        self.hbox4.addLayout(self.hflo31)
        self.hbox4.addLayout(self.hflo32)
        self.hbox4.setSpacing(0)
        ###############6. 添加垂直布局
        self.vbox = QVBoxLayout()
        self.vbox.addLayout(self.vflo)
        # self.vbox.addLayout( self.vfl1 )
        ###################### 添加布局
        vlayout = QVBoxLayout()  # 整个程序的灵魂,将QVBoxLayout改成QHBoxLayout可以改变hbox和vbox的布局从垂直布局到水平布局
        vlayout.addLayout(self.hbox)  # 组合第一排
        vlayout.addLayout(self.hbox2)  # 组合第二排
        vlayout.addLayout(self.hbox3)  # 组合第二排
        vlayout.addLayout(self.hbox4)  # 组合第二排
        vlayout.addLayout(self.vbox)  # 组合第三列
        self.setLayout(vlayout)
        self.textEdit.setFontPointSize(15)  # 设置富文本的字体大小
        self.textEdit.setReadOnly(False)  # 设置为只读、可写
        self.textEdit.setTextBackgroundColor(QColor(80, 80, 80))  # 设置文字背景色
        self.textEdit.setTextColor(QColor(200, 220, 180))  # 设置文字颜色
        ################################################
        """信号绑定"""  ###信号绑定必须也函数一一对应,否则不显示窗口
        self.selExcel.clicked.connect(self.choose_file)  # 选择文件
        self.pushGO.clicked.connect(self.load_file)  #执行文件
        self.pushSee.clicked.connect(self.load_See)  #查绚结果
        # # self.jsGO.clicked.connect(self.__onClickejyGO)    #极速录单
        # self.chromedebug.clicked.connect(self.__chromedebug)  # 谷歌浏览器
        # self.pushIMGSY.clicked.connect(self.__pushIMGSY)  # 图片压缩
        # #self.lineEdit.clicked.connect(self.__lineEdit)  # 图片压缩
        # self.lineEdit.returnPressed.connect(self.__lineEdit)#路经显示回车激活函数

    #####################################################################
    def choose_file(self):
        try:
            '''选择EXCEL文件'''
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            file_name, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel files (*.xlsx)", options=options)
            if file_name:
               # print(file_name)
                self.lineExcel.setText(file_name)
                self.file_name = file_name
                df = pd.read_excel(self.file_name)
                # 读取原表的列名并生成列表
                list_df = list(df)
                # 以原列列表为基础,生成大写字母的同量列表
                list_dfmap = list(map(chr, range(65, 65 + len(list_df))))
                # 交两个列表合并生成新的对应字典,方便后面以大写字母调用列名
                Clist = dict(zip(list_dfmap, list_df))
                print(Clist)
                self.textEdit.setText('提示:从下面的对应关系上选择分组与合并列\n'  + str(Clist))
        except:
            print('文件选择出错')




    def load_file(self):
        try:
            self.close_excel_file(self.output)
            '''加载EXCEL文件,写入列表名'''
            print('开始载入列名')
            # 读取Excel文件
            if len(self.file_name) <=0:
                print('请选择需要处理的表格文件')
                QMessageBox.information(self, '提示', "请选择需要处理的表格文件")
            else:
                print(self.file_name)
                #读取表格内容,并将Dataframe利用applymap(str)函数全部转为字符串格式,以防报错
                df = pd.read_excel(self.file_name).applymap(str)
                # 读取原表的列名并生成列表
                list_df = list(df)
                # 以原列列表为基础,生成大写字母的同量列表
                list_dfmap = list(map(chr, range(65, 65 + len(list_df))))
                # 交两个列表合并生成新的对应字典,方便后面以大写字母调用列名
                Clist = dict(zip(list_dfmap, list_df))
                print(Clist)
                #读取分组的列名大写字母
                see_Group = self.listGroup.get_selected()
                # 读取合并的列名大写字母
                see_Merge = self.listMerge.get_selected()
                # 跟据用户选择的分组,合并列的大写字木,在字母列名的字典里读取出来,生成各自列表
                hb_name = list(Clist.get(i) for i in see_Group)
                hb_value = list(Clist.get(i) for i in see_Merge)
                print(hb_name)
                print(hb_value)
                #检查分组和合并两个列表是否有交集,并返回交集
                list_c = list(set(see_Group) & set(see_Merge))
                print(list_c)
                # 通过交集列表长度判断,如果有交集则返回提示信息,否则执行后面操作
                if len(list_c) >= 1:
                    QMessageBox.information(self, '提示', "分组与合并列不能有重合{}".format(list_c))
                else:
                    print('开始进行分组合并操作')
                    if len(see_Group) >=1:
                        print('分组列非空,执行下面代码')
                        if len(see_Merge) >=1:
                            print('合并列非空,执行分组合并任务')
                            # 生成合并字典式,value_y为合并里面的代码,只能用字典
                            value_y = {'one': lambda x: '、'.join(set(x))}
                            # print(value_y)
                            print(value_y)
                            # 通常用来初始化字典, 设置value的默认值,
                            value = dict.fromkeys(hb_value, value_y.get('one'))
                            # 按照hb_name列进行分组,并将hb_value里的所有列分别合并为一个逗号分隔的字符串,同时去重,转换为DataFrame
                         #   result = df.groupby(hb_name).agg(value)
                            result = df.groupby(hb_name).agg(value)
                            # 将原数据按名子分组
                            df1 = df.drop_duplicates(subset=hb_name)
                            # 将result与原始数据按照name列进行合并,保留其他列的内容
                            result = pd.merge(df1.drop(columns=hb_value).drop_duplicates(), result, on=hb_name)
                            # 按最原表的列顺序展示新表,list_df为原表的列表
                            result = result[list_df]
                            print(result)
                            result.to_excel(self.output, index=False)
                            QMessageBox.information(self, '提示', "以{}分组,以{}合并完成".format(hb_name,hb_value))

                        else:
                            print('合并列为空,单执行分组任务')
                            # 将原数据按名子分组
                            hb_Group = df.drop_duplicates(subset=hb_name)
                            print(hb_Group)
                            hb_Group.to_excel(self.output, index=False)
                            QMessageBox.information(self, '提示', "以{}分组完成".format(hb_name))
                    else:
                        print('分组列为空,请选择')
                        QMessageBox.information(self, '提示', "分组列为空,请选择")
        except:
            print('执行分组合并出错')

    def load_See(self):
        try:
            #查询结果
            print("查询结果开始")
            # 打开查询到的数据表格
            print(self.output)

            os.startfile(self.output)
            #self.close_excel_file(self.output)  # 关掉OUT表

        except:
            print('查询结果出错')
    def close_excel_file(self,closeexcel):
        #关掉指定的表格文件
        xlApp = Dispatch('Excel.Application')
        xlApp.DisplayAlerts = False  # 设置不显示警告和消息框
        # xlBook = xlApp.Workbooks.Open(file)
        workbooks_n = xlApp.Workbooks.Count
        print(f'已打开工作簿的数量为:{workbooks_n}个')

        if workbooks_n < 0: return

        for i in range(1, workbooks_n + 1):  # 工作簿索引从1开始
            path_ = xlApp.Workbooks(i).Path
            name_ = xlApp.Workbooks(i).Name
            path = path_ + "\\backup_" + name_
            # print(f'第{i}个excel的文件路径为:{path}')
            if (closeexcel in path):
                xlApp.Workbooks(i).Close() #关闭当前打开的文件,不保存文件
               # xlApp.Workbooks(i).Activate()
                #xlApp.Workbooks(i).SaveAs(path)
                #xlApp.Workbooks(path).Close()

        # xlApp.Quit()  #关闭所有打开的excel文件
        del xlApp

if __name__ == "__main__":
    try:

        app = QApplication(sys.argv)
        serverName = 'testEvaluatinoServer601'
        socket = QLocalSocket()
        socket.connectToServer(serverName)
        # 如果连接成功,表明server已经存在,当前已有实例在运行
        if socket.waitForConnected(601):
            app.quit()

        else:
            localServer = QLocalServer()  # 没有实例运行,创建服务器
            localServer.listen(serverName)
            dialog = MyDialog()
            dialog.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)  # 窗口置顶
            dialog.show()
            dialog.setWindowTitle('Excel分组合并 by.182294401')

            # dialog.move( int( rc.read_config()[7] ), int( rc.read_config()[8] ) )  # 窗口靠右
          #  dialog.resize(600, 500)  # 显示框大小
            sys.exit(app.exec_())
            pass
    except:
        pass

免费评分

参与人数 3吾爱币 +7 热心值 +3 收起 理由
苏紫方璇 + 5 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
mcq1998 + 1 + 1 我很赞同!
luozi1653 + 1 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

keithu 发表于 2023-5-17 23:16
有没有一个浅显的功能说明?
yu520 发表于 2023-5-18 08:39
abc023119 发表于 2023-5-18 09:12
lingwushexi 发表于 2023-5-18 09:20
感谢分享
pangdundun 发表于 2023-5-18 13:52
咳,拿来主义了解下PyQt
 楼主| tkdahai 发表于 2023-5-19 20:19
keithu 发表于 2023-5-17 23:16
有没有一个浅显的功能说明?

首先选择需要操作的表格,1.按列名分组,可以一列也可以多列,2.在分组的基础上,合并需要的列的数据,并以顿号分开,同时去掉重复数据。
 楼主| tkdahai 发表于 2023-5-19 20:52
分享成品下截地址:https://share.weiyun.com/XilMJc4u
无标题.png
isunfly 发表于 2024-8-25 11:03
收藏一下,后续使用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 13:53

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表