使用 Python 寻找一种基于用户输入更快地从 Excel Table 中提取信息的方法

Finding a Way to Pull Information From an Excel Table Based on User Inputs Quicker Using Python

我会尽力解释这一点,但我预计我将不得不改写几次。

所以我拥有的是具有特定规格的图表列表。我在 Excel 中构建了一个包含各种图表及其规格的 table。我使用 PySimpleGui 构建了一个 GUI 供用户交互。有下拉框,其中包含规范,它们将用作代码的输入,用于搜索这些图表。这是 GUI

的代码
#To create the GUI, first the layout of the window must be set up.
#Set the theme
psg.theme('LightBlue')

#Create a list that will be used for the listbox
diag_num = []
Torq = []

#Set up the layout
left_col = [[psg.Text('Choose the Type: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','CSIR','CSCR', 'PSC', 'Poly', 'SP'], font='Helvetica',
    default_value='Select Option', key='type')],
    [psg.Text('Choose the TORQ Switch: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','282070101', '282070111', '282070117', '282070118', '282070125', '282070201','282070205','282070251',
    '282070261', '282070303', '282070304', '282070352', '282070403', '282070451', '282070600', '282070601', '282070602', '282070701', '282070702', '282070901', '282070902', '282070903', '282080101', 'None'],
     font='Helvetica', default_value='Select Option', key='switch')],
    [psg.Text('Is there a Terminal Board: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option', 'Yes', 'No'], font ='Helvetica', default_value='Select Option',
    key='board')],
    [psg.Text('Choose the Voltage: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','Single','Double'], font='Helvetica',
    default_value='Select Option', key='volt')],
    [psg.Text('Choose the Rotation: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','Non-Reversible','Reversible'], font='Helvetica',
    default_value='Select Option', key='rot')],
    [psg.Text('Choose the Start: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','Total','Half'], font='Helvetica', default_value='Select Option',
    key='start')],
    [psg.Text('Choose the Overload: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','Disc','Lace-On','None'], font='Helvetica',
    default_value='Select Option', key='overl')],
    [psg.Text('Choose the Assembly Voltage: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option', 'HI', 'LO', 'FX', 'None'], font='Helvetica',
    default_value='Select Option', key='assymv')],
    [psg.Text('Choose the Lead End: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option','CW','CCW', 'REV', 'None'], font='Helvetica', default_value='Select Option',
    key='lead')],
    [psg.Text('Choose an Auxiliary Switch: ', size=(25,2), font='Helvetica', justification='left'), psg.Combo(['Select Option', 'Air', 'Line', 'Mech', 'On/Off', 'Pull Chain',
    'Relay', 'Rocker', 'SIMPAC', 'SSS', 'TRIAC', 'Volt', 'Multiple', 'None'], font='Helvetica', default_value='Select Option', key='auxsw')],
    [psg.Button('Search', font=('Helvetica')), psg.Button('Reset', font=('Helvetica')), psg.Exit(font=('Helvetica'))]]

right_col = [[psg.Listbox(values = diag_num, enable_events=True, font='Helvetica', select_mode = 'LISTBOX_SELECT_MODE_SINGLE', key='ConnDiag', size=(20,22))],
    [psg.Text('', size=(25,0))]]

layout = [[psg.Column(left_col, element_justification='c'), psg.Column(right_col, element_justification='c')]]
#Define the window
win = psg.Window('Connection Diagram Picker', layout, resizable=True)

程序然后将这些输入转换为 1 和 0,以便处理用户是否将下拉框作为简单的“Select 选项”而不是提供输入。这样他们就可以在不精确搜索的情况下搜索图表。这是相关代码:

if event == 'Search': #Searches based on combo values
        
        '''
        This event happens when the user clicks on the Search button in the GUI.
        When this happens, the program assigns the user inputs a Boolean value based on 1s and 0s.
        It then uses these values to perform basic logical tests to search through the Excel documents,
        to find the Connection diagram that matches that criteria input by the user.
        '''
        win['ConnDiag'].update([''])

        if v['switch'] != 'None' and v['switch'] != 'Select Option':
            switch = int(v['switch'])
        else:
            switch = v['switch']

        # Convert the inputs into Boolean logic assigned 1s and 0s
        if v['type'] == 'Select Option': typeBool = 0
        else: typeBool = 1
        
        if v['switch'] == 'Select Option': switchBool = 0
        else: switchBool = 1

        if v['board'] == 'Select Option': boardBool = 0
        else: boardBool = 1
        
        if v['volt'] == 'Select Option': voltBool = 0
        else: voltBool = 1

        if v['rot'] == 'Select Option': rotBool = 0
        else: rotBool = 1

        if v['start'] == 'Select Option': startBool = 0
        else: startBool = 1

        if v['overl'] == 'Select Option': overlBool = 0
        else: overlBool = 1
        
        if v['assymv'] == 'Select Option': assymvBool = 0
        else: assymvBool = 1

        if v['lead'] == 'Select Option': leadBool = 0
        else: leadBool = 1
        
        if v['auxsw'] == 'Select Option': auxswBool = 0
        else:auxswBool = 1

从那里开始,代码与 Excel table 使用 Pandas 交互。它将获取下拉框中的值并通过 Excel table 执行搜索以查找包含用户输入的这些规格的图表。然后它将拉出这些图表的列表并将它们显示在列表框中。

# ---------------------------------------------------------------- All True ---------------------------------------------------------------- #

        if typeBool == 1 and switchBool == 1 and boardBool == 1 and voltBool == 1 and rotBool == 1 and startBool == 1 and overlBool == 1 and assymvBool == 1 and leadBool == 1 and auxswBool == 1:

            #Declare looping variables
            i = 0

            diag_num.clear()
            Torq.clear()

            while i < len(workbook):
                
                if workbook['Type:'][i] == v['type'] and workbook['TORQ:'][i] == switch and workbook['Voltage:'][i] == v['volt'] and workbook['Rotation:'][i] == v['rot'] and workbook['Start:'][i] == v['start'] and workbook['Overload:'][i] == v['overl'] and workbook['Assembly Voltage:'][i] == v['assymv'] and workbook['Lead:'][i] == v['lead'] and workbook['Aux Switch:'][i] == v['auxsw']:

                    #Read through the Excel file to find the matching diagrams and append the list.
                    diag_num.append(workbook['Connection Diagram:'][i])
                    Torq.append(workbook['TORQ:'][i])
                
                i += 1

            diagNum, torq = DelDupl(diag_num,Torq)

            if len(diagNum) == 0:
                psg.popup('ERROR!', 'No connection diagram found!')

            win['ConnDiag'].update(values = diagNum)

            if v['ConnDiag']:

                UserChoice = v['ConnDiag'][0]
                UserChoice = BuildFile(UserChoice)
                readFile(UserChoice)

        # ---------------------------------------------------------------- One True ---------------------------------------------------------------- #

        if typeBool == 1 and switchBool == 0 and boardBool == 0 and voltBool == 0 and rotBool == 0 and startBool == 0 and overlBool == 0 and assymvBool == 0 and leadBool == 0 and auxswBool == 0:

            #Declare looping variables
            i = 0

            diag_num.clear()
            Torq.clear()

            while i < len(workbook):

                if workbook['Type:'][i] == v['type']:

                    #Read through the Excel file to find the matching diagrams and append the list.
                    diag_num.append(workbook['Connection Diagram:'][i])
                    Torq.append(workbook['TORQ:'][i])
                
                i += 1

            diagNum, torq = DelDupl(diag_num,Torq)

            win['ConnDiag'].update(values = diagNum)

            if v['ConnDiag']:

                UserChoice = v['ConnDiag'][0]
                UserChoice = BuildFile(UserChoice)
                readFile(UserChoice)

这只是一小段代码。它不断向前,在 1 和 0 之间交替,基本上创造了一个巨大的真理 table,根据列表框是否有用户输入,事情会发生。然后代码检查这些输入是什么,然后通过 Excel table 查找具有与用户输入匹配的规范的图表。这里面的功能应该不会有太大的区别,因为它们只是删除重复项并搜索图表的 pdf。

所以,事情是这样的,我的代码有效。它工作没有问题,因此不需要修复。不过,我 运行 感兴趣的是,随着我拥有的连接图的数量及其规格,我想确保将来可以轻松地添加或减去更多的图,而不会过多地混淆代码,我这些 1 和 0 可以采用 1000 多种不同的组合。这里的每个块大约需要 30 行代码,所以当我完成时我将有近 40,000 行代码。我大约有 11,000 行代码,而且制作起来花费的时间太长了。代码运行良好,而且还不慢。但我想找到一种压缩代码的方法,这样我就不会疯狂地尝试复制粘贴并编辑这么多代码。我知道必须有办法,但我似乎不知道该怎么做。

不确定是什么问题...,但这里可能有一些帮助。

对于带有文本和组合的许多行,几乎所有相同的选项,所以采用以下布局方式可能更好。

import PySimpleGUI as psg

item_dict = {
    "type"   :  ('Choose the Type: ',
                ['Select Option', 'CSIR', 'CSCR', 'PSC', 'Poly', 'SP']),
    "switch" :  ('Choose the TORQ Switch: ',
                ['Select Option', '282070101', '282070111', '282070117', '282070118',
                                  '282070125', '282070201', '282070205', '282070251',
                                  '282070261', '282070303', '282070304', '282070352',
                                  '282070403', '282070451', '282070600', '282070601',
                                  '282070602', '282070701', '282070702', '282070901',
                                  '282070902', '282070903', '282080101', 'None']),
    "board"  :  ('Is there a Terminal Board: ',
                ['Select Option', 'Yes', 'No']),
    "volt"   :  ('Choose the Voltage: ',
                ['Select Option', 'Single', 'Double']),
    "rot"    :  ('Choose the Rotation: ',
                ['Select Option', 'Non-Reversible', 'Reversible']),
    "start"  :  ('Choose the Start: ',
                ['Select Option', 'Total', 'Half']),
    "overl"  :  ('Choose the Overload: ',
                ['Select Option', 'Disc', 'Lace-On', 'None']),
    "assymv" :  ('Choose the Assembly Voltage: ',
                ['Select Option', 'HI', 'LO', 'FX', 'None']),
    "lead"   :  ('Choose the Lead End: ',
                ['Select Option', 'CW', 'CCW', 'REV', 'None']),
    "auxsw"  :  ('Choose an Auxiliary Switch: ',
                ['Select Option', 'Air', 'Line', 'Mech', 'On/Off', 'Pull Chain',
                                  'Relay', 'Rocker', 'SIMPAC', 'SSS', 'TRIAC',
                                  'Volt', 'Multiple', 'None']),
}

item_list = ["type", "switch", "board", "volt", "rot", "start", "overl", "assymv",
    "lead", "auxsw" ]

font = ('Helvetica', 11)
psg.theme('LightBlue')
psg.set_options(font=font)


left_col = []
for item in item_list:
    item_text, item_list = item_dict[item]
    left_col.append([
        psg.Text(item_text, size=(25, 2)),
        psg.Combo(item_list, default_value=item_list[0], key=item),
    ])
left_col.append([psg.Button(text) for text in ('Search', 'Reset', 'Exit')])

right_col = [
    [psg.Listbox(values=diag_num, enable_events=True, key='ConnDiag', size=(20,22))],
    [psg.Text('', size=(25, 0))],
]

layout = [
    [psg.Column(left_col,  element_justification='c'),
     psg.Column(right_col, element_justification='c')],
]

win = psg.Window('Connection Diagram Picker', layout, resizable=True)

对于很多情况要检查是否全部为真,请尝试使用内置函数 all,对于您的情况

"""
# Replace code here by only one `all` statement
# Convert the inputs into Boolean logic assigned 1s and 0s
if v['type'] == 'Select Option': typeBool = 0
else: typeBool = 1

if v['switch'] == 'Select Option': switchBool = 0
else: switchBool = 1

...

if v['auxsw'] == 'Select Option': auxswBool = 0
else:auxswBool = 1

# ---------------------------------------------------------------- All True ---------------------------------------------------------------- #

if typeBool == 1 and switchBool == 1 and boardBool == 1 and voltBool == 1 and rotBool == 1 and startBool == 1 and overlBool == 1 and assymvBool == 1 and leadBool == 1 and auxswBool == 1:
"""
if all(map(lambda x:x != 'Select Option', item_list)):

同样,如果您对 item_list 中的工作簿和项目之间的映射进行了良好的设置,函数 all 仍然适用于您,也许像这样

if all(map(lambda x:workbook['Type:'][i] == v[x], item_list)):

我认为您正在“艰难地”解决这个问题。任何时候您需要(手动)枚举大量案例,都可能有更好的方法。

所以下面假设您有一个包含所有信息的良好数据框,我认为您这样做是为了匹配选择。

这里的关键(如果您使用 pandas...如果您在字典等中有项目描述,还有其他方法)是使用 pandas 查询来匹配选择。您可以从组合框中手动创建此查询(正如我在下面所做的那样)并自动忽略未选择的而不是写出案例。

请注意,我只是在这里制作一个链接到数据的按钮列表,您可以手动制作按钮,这很好。正如我在评论中指出的那样,如果您的 window 值中有其他与搜索条件无关的项目,则需要在构建查询之前从值中省略它们。

下面的内容在我的机器上按预期运行并包含玩具数据。有问题评论回来! :)

# gui search
import pandas as pd
import PySimpleGUI as psg

# some data

data = {    'Type':     ['CSIR', 'CSIR', 'Poly', 'Poly'],
            'Voltage':  ['Single', 'Single', 'Single', 'Double'],
            'Rotation': ['Reversible', 'Reversible', 'Non-Rev', 'Non-Rev'],
            'Diag':     [45, 63, 2001, 897]}

df = pd.DataFrame(data).set_index('Diag')
print(df)

# Some mock-up buttons....  use the df values...
psg.theme=('LightBlue')

buttons = {}
for c in df.columns:
    default='Select One'
    values = list(set(df[c]))
    b = psg.Combo(values=values, key=c, default_value=default)
    buttons[c] = b

# add the buttons from the list into your window...  This could be done several ways
# you could reference these buttons in your layout list individually, etc...
layout = []
for c in df.columns:
    layout.append([buttons[c],])
layout.append([psg.Button('Search'),])

win = psg.Window('example', layout)
e, v = win.read()
win.close()
print(v)

# make a query string for use with pandas dataframe query...
query = ""
# drop the ones that were not selected...
# note if you have other value objects in v besides the search items,
# you will need to remove them somehow
v = {k:v for k,v in v.items() if v != default}
for k, v in v.items():
    query += f'{k} == "{v}" and '
query += "True"  # cheap way of satisfying the last "AND"

print("\nmatches:")
result = df.query(query)
print(result)

print("\n\nget diagrams...:")
for diag in result.index.to_list():
    print('  ' + str(diag))

输出

(仅从电压组合中选择“单一”):

matches:
      Type Voltage    Rotation
Diag                          
45    CSIR  Single  Reversible
63    CSIR  Single  Reversible
2001  Poly  Single     Non-Rev


get diagrams...:
  45
  63
  2001

我最终弄清楚了我需要做什么。我最终使用列表并根据用户输入值将信息转储到列表中。然后从那里,代码检查每个列表中是否存在所有列表中存在的项目,然后 returns 那些。

i = 0
j = 0

   while i < len(workbook):

        l_conn.append(workbook['Connection Diagram:'][i])
        l_TORQ.append(workbook['TORQ:'][i])

        if v['type'] == 'Select Option':
            l_type.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Type:'][i] == v['type']:
                l_type.append(workbook['Connection Diagram:'][i])

        if v['switch'] == 'Select Option':
            l_torq.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['TORQ:'][i] == int(v['switch']):
                l_torq.append(workbook['Connection Diagram:'][i])

        if v['board'] == 'Select Option':
            l_board.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Board:'][i] == v['board']:
                l_board.append(workbook['Connection Diagram:'][i])

        if v['volt'] == 'Select Option':
            l_volt.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Voltage:'][i] == v['volt']:
                l_volt.append(workbook['Connection Diagram:'][i])

        if v['rot'] == 'Select Option':
            l_rot.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Rotation:'][i] == v['rot']:
                l_rot.append(workbook['Connection Diagram:'][i])

        if v['start'] == 'Select Option':
            l_start.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Start:'][i] == v['start']:
                l_start.append(workbook['Connection Diagram:'][i])

        if v['overl'] == 'Select Option':
            l_overl.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Overload:'][i] == v['overl']:
                l_overl.append(workbook['Connection Diagram:'][i])

        if v['assymv'] == 'Select Option':
            l_assymv.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Assembly Voltage:'][i] == v['assymv']:
                l_assymv.append(workbook['Connection Diagram:'][i])

        if v['lead'] == 'Select Option':
            l_lead.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Lead:'][i] == v['lead']:
                l_lead.append(workbook['Connection Diagram:'][i])

        if v['auxsw'] == 'Select Option':
            l_auxsw.append(workbook['Connection Diagram:'][i])
        else:
            if workbook['Aux Switch:'][i] == v['auxsw']:
                l_auxsw.append(workbook['Connection Diagram:'][i])

        i += 1

    while j < len(l_conn):

        if l_conn[j] in l_type and l_conn[j] in l_torq and l_conn[j] in l_board and l_conn[j] in l_volt and l_conn[j] in l_rot and l_conn[j] in l_start and l_conn[j] in l_overl and l_conn[j] in l_assymv and l_conn[j] in l_lead and l_conn[j] in l_auxsw:

            diag_num.append(l_conn[j])
            Torq.append(l_TORQ[j])

        j += 1