简体   繁体   English

使用 openpyxl 排序

[英]Sorting with openpyxl

I am trying to sort columns from least to greatest using openpyxl.我正在尝试使用 openpyxl 从最小到最大对列进行排序。 I am open to using other libraries to accomplish this.我愿意使用其他库来完成此任务。 Here is the code that I have right now, however, nothing is being sorted.这是我现在拥有的代码,但是没有任何排序。

from openpyxl import load_workbook

wb=load_workbook('NotSorted.xlsx')
ws1=wb.get_sheet_by_name('Mean')

ws1.auto_filter.add_sort_condition('J2:J21')

wb.save('Sorted.xlsx')

Any help is greatly appreciated!任何帮助是极大的赞赏!

You can sort using win32com.client (install it with pip install pypiwin32 ).您可以使用win32com.client进行排序(使用pip install pypiwin32 )。

Example workbook named MyWorkbook.xlsx with contents (before and after):名为MyWorkbook.xlsx示例工作簿包含内容(之前和之后):

排序前 排序后

import win32com.client

excel = win32com.client.Dispatch("Excel.Application")

wb = excel.Workbooks.Open('MyWorkbook.xlsx')
ws = wb.Worksheets('Sheet1')

ws.Range('A2:A9').Sort(Key1=ws.Range('A1'), Order1=1, Orientation=1)

wb.Save()
excel.Application.Quit()

If you don't want to alter the original workbook, use SaveAs() or create another workbook and copy data like so: ws_from.Range("A1:AF100").Copy(ws_to.Range("A1:AF100")) (with appropriate range).如果您不想更改原始工作簿,请使用SaveAs()或创建另一个工作簿并复制数据,如下所示: ws_from.Range("A1:AF100").Copy(ws_to.Range("A1:AF100")) (具有适当的范围)。

See these documentation links for more information about Sort() and its parameters:有关Sort()及其参数的更多信息,请参阅这些文档链接:

The openpyxl documentation clearly states: openpyxl 文档明确指出:

This will add the relevant instructions to the file but will neither actually filter nor sort.这会将相关指令添加到文件中,但实际上既不会过滤也不会排序。

So you would need to compute the new sequence of rows and move the data explicitly (ie assigning the cells to their new positions).因此,您需要计算新的行序列并显式移动数据(即将单元格分配到它们的新位置)。

There seems to be no built-in function to sort within openpyxl but the function below will sort rows given some criteria:似乎没有内置函数可以在 openpyxl 中进行排序,但下面的函数将根据某些条件对行进行排序:

def sheet_sort_rows(ws, row_start, row_end=0, cols=None, sorter=None, reverse=False):
""" Sorts given rows of the sheet
    row_start   First row to be sorted
    row_end     Last row to be sorted (default last row)
    cols        Columns to be considered in sort
    sorter      Function that accepts a tuple of values and
                returns a sortable key
    reverse     Reverse the sort order
"""

bottom = ws.max_row
if row_end == 0:
    row_end = ws.max_row
right = get_column_letter(ws.max_column)
if cols is None:
    cols = range(1, ws.max_column+1)

array = {}
for row in range(row_start, row_end+1):
    key = []
    for col in cols:
        key.append(ws.cell(row, col).value)
    array[key] = array.get(key, set()).union({row})

order = sorted(array, key=sorter, reverse=reverse)

ws.move_range(f"A{row_start}:{right}{row_end}", bottom)
dest = row_start
for src_key in order:
    for row in array[src_key]:
        src = row + bottom
        dist = dest - src
        ws.move_range(f"A{src}:{right}{src}", dist)
        dest += 1

Call it with the worksheet and start row to be sorted as a minimum.用工作表调用它并开始作为最小排序的行。 By default it'll sort on all columns A...max in that order but this can be changed by passing a 'cols' list.默认情况下,它将按该顺序对所有列 A...max 进行排序,但这可以通过传递“cols”列表来更改。 Eg [4, 2] will sort first on D then on B.例如 [4, 2] 将首先在 D 上排序,然后在 B 上排序。

Sort order can be reversed using 'reverse' as with 'sorted()'.可以使用 'reverse' 反转排序顺序,就像使用 'sorted()' 一样。

If you need more complex sorting, provide a 'sorter' function.如果您需要更复杂的排序,请提供“排序器”功能。 This receives a tuple of values (being those from the 'cols' columns) and should return a sortable key.这会接收一个值元组(来自“cols”列的值)并且应该返回一个可排序的键。

It works by ascertaining the desired final destination of each row, moving them all down below the current worksheet, then moving them back to the required destination.它的工作原理是确定每行所需的最终目的地,将它们全部向下移动到当前工作表下方,然后将它们移回所需的目的地。

I wanted all columns in each row, but modifying to move a smaller area can be accomplished by changing the two calls to ws.move_range().我想要每行中的所有列,但是可以通过将两次调用更改为 ws.move_range() 来修改以移动较小的区域。

Examples:例子:

sheet_sort_rows(ws, 5, 10)  # Sort rows 5-10 using key: A, B, C, ...
sheet_sort_rows(ws, 5, 10, [2, 1])  # Sort rows using B, A
sheet_sort_rows(ws, 5, 10, [2, 1], reverse=True)  # As above in reverse


def sorter(t):
    return t[1] + " " + t[0][::-1]

sheet_sort_rows(ws, 5, 10, sorter=sorter)

This last sorts by column B followed by column A reversed.最后按 B 列排序,然后 A 列颠倒。

I tried to use the sheet_sort_rows function above but got an exception on array[key] = array.get(key, set()).union({row}) : List is not hashable (using Python 3.10 and Openpyxl 3.0.9)我尝试使用上面的sheet_sort_rows function 但在array[key] = array.get(key, set()).union({row})上出现异常:列表不可散列(使用 Python 3.10 和 Openpyxl 3.0.9)

As a workaround I'm using the key as a string (concat of all column values converted to str).作为一种解决方法,我将键用作字符串(所有列值的连接转换为 str)。 Not as good as the original idea, and can't use a sorter function to sort some columns in default order and others in reverse order.不如最初的想法,并且不能使用排序器 function 按默认顺序对某些列进行排序,而另一些则按相反的顺序排序。

Would be nice to have the original working but I don't have a clue (new in python...)如果能使用原始版本就好了,但我不知道(python 中的新功能...)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM