如何对 excel 中的行值进行排序并在其他地方显示相应的列名?
How to sort row values in excel and display corresponding column names elsewhere?
基本上,我有这样的 excel sheet -
A B C D
16 14 13 12
14 14 13 14
16 14 15 12
14 14 15 14
我想让 excel sheet 显示这个 -
A B C D
16 14 13 12 A B C D
14 14 13 14 A B D C
16 14 15 12 A C B D
14 14 15 14 C A B D
换句话说,在每一行旁边,我想要列名的降序排列。我如何实现这一目标?我尝试了几种不同的排序方式,但 none 在另一列中给出了列名,就像我想要的那样。请帮忙。
我用的是Excel2007.
编辑:
经过this post后,我用了
=INDEX(L:S,MATCH(LARGE(L42:S42,1),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,2),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,3),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,4),L42:S42,0))
显示每行4个最大值对应的列名。但是话又说回来,当 2 个或更多值相等时,我得到这样的输出 -
A B C D
16 14 13 12 A B C D
14 14 13 14 A A A C
16 14 15 12 A C B D
14 14 15 14 C A A A
我该如何解决这个问题以获得我想要的输出(我在开头说明的)?
在确定第 LARGE
个值时,您必须考虑值的位置。如果值相等,则您必须确定第一个相等值是否也应在列表中排在第一位。
如果只有整数值,那么我们可以将值的位置取为小数位。
示例:
E2
中的公式,交叉复制到 E2:H5
:
{=INDEX($A:$D,MATCH(LARGE($A2:$D2+(10-COLUMN($A2:$D2))/10,E),$A2:$D2+(10-COLUMN($A2:$D2))/10,0))}
这是一个数组公式。不输入大括号,然后按 [Ctrl]+[Shift]+[Enter].
结束
这仅适用于最多 10 列。如果更多列,部分 (10-...)/10
必须更改为 (100-...)/100
。
在这个例子中,第一个相等的值也在列表中排在第一位。如果最后一个相等的值应在列表中排在第一位,则删除 10-
部分。
可以使用条件格式突出显示具有相同值的列名。
- Select
E2:H6
.
- 调用条件格式。
- 使用公式应用新规则,公式:
=COUNTIF($A2:$D2,INDEX($A2:$D2,MATCH(LARGE($A2:$D2,E),$A2:$D2,0)))>1
- Select 你想要的格式。
这是一个VBA方法。它将 table 中数据值的位置与列标签相关联;对数据值进行 stable 排序;和 returns 列标签。
一个潜在的优势是它适用于文本或数值;如果需要,可以区分大小写。
这取决于table从A1开始的数据,并且A列或第1行的作品sheet没有其他内容;因为它使用这些范围来确定要处理的最后一行和最后一列。
要输入此宏(子),alt-F11
打开 Visual Basic 编辑器。
确保您的项目在 Project Explorer window.
中突出显示
首先,从顶部菜单中,select Insert/Class Module
并将下面的 Class 模块 代码粘贴到 window打开。 Select Class 模块并重命名(点击 F4
并更改 Name
属性)cRow
.
然后,从顶部菜单中,select Insert/Module
并将下面的 常规模块 代码粘贴到 window.
要使用此宏(子),请确保您的数据显示在活动 sheet 上。然后 alt-F8
打开宏对话框。 Select 宏的名称,以及 .
Class 模块
Option Explicit
Private pData As Variant
Private pColLabel As String
Public Property Get Data() As Variant
Data = pData
End Property
Public Property Let Data(Value As Variant)
pData = Value
End Property
Public Property Get ColLabel() As String
ColLabel = pColLabel
End Property
Public Property Let ColLabel(Value As String)
pColLabel = Value
End Property
常规模块
Option Explicit
Option Compare Text
Sub SortAndColLabel()
Dim vSrc As Variant, vRes() As Variant
Dim cR As cRow, colR As Collection
Dim LastRow As Long, LastCol As Long
Dim R As Range
Dim I As Long, J As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
LastCol = Cells(1, Columns.Count).End(xlToLeft).Column
vSrc = Range(Cells(1, 1), Cells(LastRow, LastCol))
ReDim vRes(1 To UBound(vSrc, 1), 1 To UBound(vSrc, 2) * 2)
'Associate entries with column labels
For I = 2 To UBound(vSrc, 1)
Set colR = New Collection
For J = 1 To UBound(vSrc, 2)
Set cR = New cRow
With cR
.ColLabel = vSrc(1, J)
.Data = vSrc(I, J)
colR.Add cR
End With
Next J
'Sort the row, need to use stable sort
CollectionBubbleSort colR
'Place in results array
For J = 1 To colR.Count
With colR(J)
vRes(I, J) = vSrc(I, J)
vRes(I, J + UBound(vSrc, 2)) = .ColLabel
End With
Next J
Next I
'Add Column Labels to Vres
For J = 1 To UBound(vSrc, 2)
vRes(1, J) = vSrc(1, J)
Next J
'Write the results
Set R = Range("a1", Cells(UBound(vRes, 1), UBound(vRes, 2)))
With R
.EntireColumn.Clear
.Value = vRes
.HorizontalAlignment = xlCenter
End With
End Sub
'---------------------------------------------------------------
'Could use faster sort routine if necessary
Sub CollectionBubbleSort(TempCol As Collection)
'Must manually insert element of collection to sort on in this version
Dim I As Long
Dim NoExchanges As Boolean
' Loop until no more "exchanges" are made.
Do
NoExchanges = True
' Loop through each element in the array.
For I = 1 To TempCol.Count - 1
' If the element is greater than the element
' following it, exchange the two elements.
If TempCol(I).Data < TempCol(I + 1).Data Then
NoExchanges = False
TempCol.Add TempCol(I), after:=I + 1
TempCol.Remove I
End If
Next I
Loop While Not (NoExchanges)
End Sub
答案已被接受,这是一个很好的答案,但为了自娱自乐,我会 post 一个变体:-
=INDEX($A:$D,MATCH(0,IF($A2:$D2=LARGE($A2:$D2,COLUMN()-COLUMN($E2)),COUNTIF($E2:E2,$A:$D),1),0))
这使用标准 COUNTIF/MATCH 方法来消除已经输入的列,并且不会对数字的大小做出任何假设。
同样是数组公式,必须用Ctrl输入Shift输入
基本上,我有这样的 excel sheet -
A B C D
16 14 13 12
14 14 13 14
16 14 15 12
14 14 15 14
我想让 excel sheet 显示这个 -
A B C D
16 14 13 12 A B C D
14 14 13 14 A B D C
16 14 15 12 A C B D
14 14 15 14 C A B D
换句话说,在每一行旁边,我想要列名的降序排列。我如何实现这一目标?我尝试了几种不同的排序方式,但 none 在另一列中给出了列名,就像我想要的那样。请帮忙。
我用的是Excel2007.
编辑:
经过this post后,我用了
=INDEX(L:S,MATCH(LARGE(L42:S42,1),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,2),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,3),L42:S42,0))
=INDEX(L:S,MATCH(LARGE(L42:S42,4),L42:S42,0))
显示每行4个最大值对应的列名。但是话又说回来,当 2 个或更多值相等时,我得到这样的输出 -
A B C D
16 14 13 12 A B C D
14 14 13 14 A A A C
16 14 15 12 A C B D
14 14 15 14 C A A A
我该如何解决这个问题以获得我想要的输出(我在开头说明的)?
在确定第 LARGE
个值时,您必须考虑值的位置。如果值相等,则您必须确定第一个相等值是否也应在列表中排在第一位。
如果只有整数值,那么我们可以将值的位置取为小数位。
示例:
E2
中的公式,交叉复制到 E2:H5
:
{=INDEX($A:$D,MATCH(LARGE($A2:$D2+(10-COLUMN($A2:$D2))/10,E),$A2:$D2+(10-COLUMN($A2:$D2))/10,0))}
这是一个数组公式。不输入大括号,然后按 [Ctrl]+[Shift]+[Enter].
结束这仅适用于最多 10 列。如果更多列,部分 (10-...)/10
必须更改为 (100-...)/100
。
在这个例子中,第一个相等的值也在列表中排在第一位。如果最后一个相等的值应在列表中排在第一位,则删除 10-
部分。
可以使用条件格式突出显示具有相同值的列名。
- Select
E2:H6
. - 调用条件格式。
- 使用公式应用新规则,公式:
=COUNTIF($A2:$D2,INDEX($A2:$D2,MATCH(LARGE($A2:$D2,E),$A2:$D2,0)))>1
- Select 你想要的格式。
这是一个VBA方法。它将 table 中数据值的位置与列标签相关联;对数据值进行 stable 排序;和 returns 列标签。
一个潜在的优势是它适用于文本或数值;如果需要,可以区分大小写。
这取决于table从A1开始的数据,并且A列或第1行的作品sheet没有其他内容;因为它使用这些范围来确定要处理的最后一行和最后一列。
要输入此宏(子),alt-F11
打开 Visual Basic 编辑器。
确保您的项目在 Project Explorer window.
首先,从顶部菜单中,select Insert/Class Module
并将下面的 Class 模块 代码粘贴到 window打开。 Select Class 模块并重命名(点击 F4
并更改 Name
属性)cRow
.
然后,从顶部菜单中,select Insert/Module
并将下面的 常规模块 代码粘贴到 window.
要使用此宏(子),请确保您的数据显示在活动 sheet 上。然后 alt-F8
打开宏对话框。 Select 宏的名称,以及 .
Class 模块
Option Explicit
Private pData As Variant
Private pColLabel As String
Public Property Get Data() As Variant
Data = pData
End Property
Public Property Let Data(Value As Variant)
pData = Value
End Property
Public Property Get ColLabel() As String
ColLabel = pColLabel
End Property
Public Property Let ColLabel(Value As String)
pColLabel = Value
End Property
常规模块
Option Explicit
Option Compare Text
Sub SortAndColLabel()
Dim vSrc As Variant, vRes() As Variant
Dim cR As cRow, colR As Collection
Dim LastRow As Long, LastCol As Long
Dim R As Range
Dim I As Long, J As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
LastCol = Cells(1, Columns.Count).End(xlToLeft).Column
vSrc = Range(Cells(1, 1), Cells(LastRow, LastCol))
ReDim vRes(1 To UBound(vSrc, 1), 1 To UBound(vSrc, 2) * 2)
'Associate entries with column labels
For I = 2 To UBound(vSrc, 1)
Set colR = New Collection
For J = 1 To UBound(vSrc, 2)
Set cR = New cRow
With cR
.ColLabel = vSrc(1, J)
.Data = vSrc(I, J)
colR.Add cR
End With
Next J
'Sort the row, need to use stable sort
CollectionBubbleSort colR
'Place in results array
For J = 1 To colR.Count
With colR(J)
vRes(I, J) = vSrc(I, J)
vRes(I, J + UBound(vSrc, 2)) = .ColLabel
End With
Next J
Next I
'Add Column Labels to Vres
For J = 1 To UBound(vSrc, 2)
vRes(1, J) = vSrc(1, J)
Next J
'Write the results
Set R = Range("a1", Cells(UBound(vRes, 1), UBound(vRes, 2)))
With R
.EntireColumn.Clear
.Value = vRes
.HorizontalAlignment = xlCenter
End With
End Sub
'---------------------------------------------------------------
'Could use faster sort routine if necessary
Sub CollectionBubbleSort(TempCol As Collection)
'Must manually insert element of collection to sort on in this version
Dim I As Long
Dim NoExchanges As Boolean
' Loop until no more "exchanges" are made.
Do
NoExchanges = True
' Loop through each element in the array.
For I = 1 To TempCol.Count - 1
' If the element is greater than the element
' following it, exchange the two elements.
If TempCol(I).Data < TempCol(I + 1).Data Then
NoExchanges = False
TempCol.Add TempCol(I), after:=I + 1
TempCol.Remove I
End If
Next I
Loop While Not (NoExchanges)
End Sub
答案已被接受,这是一个很好的答案,但为了自娱自乐,我会 post 一个变体:-
=INDEX($A:$D,MATCH(0,IF($A2:$D2=LARGE($A2:$D2,COLUMN()-COLUMN($E2)),COUNTIF($E2:E2,$A:$D),1),0))
这使用标准 COUNTIF/MATCH 方法来消除已经输入的列,并且不会对数字的大小做出任何假设。
同样是数组公式,必须用Ctrl输入Shift输入