转置列
我有一个CSV文件,看起来像这样:
name, a v1, 1 name, b v1, 1 v2, 5 name, c v1, 4 v2, 6 name, d v2, 8 v3, asdf
使用Excel或LibreOffice,我怎样才能将其转换为:
name, v1, v2, v3 a, 1, , b, 1, 5, c, 4, 6, d, , 8, asdf
我一直在寻找关键字转置,但它似乎不是正确的关键字来search – 所有的指南只显示如何做一个完整的转置,这是不是我想要的。
我也发现这个问题,但它假定非常干净的数据,必须手动调整的列数: Excel中的特定移调
我不知道列的数量,有些单元格可能会丢失。
我的公式为基础的方法与以下数据布局:
列A
和B
从CSV文件导入。
助手C
列中的公式:
=IF(A2="name",B2,C1)
F1
和F2
公式计算A
和C
列中的唯一条目,不需要创build输出表(这两个数组公式都用Ctrl
+ Shift
+ Enter
):
=SUM(1/COUNTIF(C2:C12,C2:C12)) =SUM(1/COUNTIF(A2:A12,A2:A12))
行标题 – C
列中的唯一值( E6
,使用Ctrl
+ Shift
+ Enter
并拖放)
=IFERROR(INDEX($C$2:$C$12, MATCH(0, COUNTIF($E$5:E5, $C$2:$C$12), 0)),"")
Colummn标题 – A
列中的唯一值( F5
, Ctrl
+ Shift
+ Enter
,然后向右拖动)
=IFERROR(INDEX($A$2:$A$12, MATCH(0, COUNTIF($E$5:E5, $A$2:$A$12), 0)),"")
两列INDEX
/ MATCH
组合填充输出表( F6
,用Ctrl
+ Shift
+ Enter
,并向右下拖动):
=IFERROR(INDEX($B$2:$B$12,MATCH(F$5&$E6,$A$2:$A$12&$C$2:$C$12,0)),"")
您需要执行两个操作来实现您的目标:
1.整理你的数据
将不同的数据types移动到单独的列。 你将有三个新的公式列:
- 名称:
=IF(A2="name",B2,C1)
- V:
=IF(A2="name","",A2)
- 值:
=IF(A2="name","",B2)
2.创build数据透视表
在这里你不能使用标准数据透视表,因为数值也可以是文本,有几个教程来创build它:
- 来自Rober Ilbrink在Stackoverflow上与VBA的回答
- 另一个来自clearlyandsimply.com与VBA的解决scheme
我从字面上理解了你的要求。 由于您想使用Excel来将CSV文件从第一个示例看起来像转换为第二个示例,所以我使用Excel VBA来:
- 打开原始的CSV文件
- 逐行阅读,并build立一个由每个
name
的项目组成的对象 - 在结果数组中插入标签线
- 重新构build由
Name
和V's
组成的Name
- 用您要求的格式将行写入新的CSV文件。
如果您在记事本中打开CSV文件,您可以看到结果。
请务必设置对Windows脚本运行时的引用来访问FileSystemObject。
Option Explicit 'SET REFERENCE to Windows Scripting Runtime ' Under Tools/References in the main menu above Sub ChangeCSV() Dim FSO As FileSystemObject, F As File, TS As TextStream Dim FN As String Dim V As Variant Dim S As String Dim vRes() As Variant Dim cI As cItem, colI As Collection Dim bFirstName As Boolean Dim I As Long, J As Long bFirstName = True 'Get File FN = Application.GetOpenFilename("CSV Files (*.csv), *.csv") 'Read file into textstream Set FSO = New FileSystemObject Set TS = FSO.OpenTextFile(FN, ForReading) Set colI = New Collection Do Until TS.AtEndOfStream S = TS.ReadLine 'Remove leading and trailing quote marks, if present 'If Left(S, 1) = """" Then S = Mid(S, 2) 'If Right(S, 1) = """" Then S = Left(S, Len(S) - 1) If Not S = "" Then 'skip empty lines V = Split(S, ",") If Trim(V(0)) = "name" Then If bFirstName = False Then colI.Add cI 'don't add if first name bFirstName = False Set cI = New cItem End If CallByName cI, CStr(Trim(V(0))), VbLet, Trim(V(1)) End If Loop colI.Add cI 'Compile results ReDim vRes(0 To colI.Count, 1 To 4) vRes(0, 1) = "Name" vRes(0, 2) = "V1" vRes(0, 3) = "V2" vRes(0, 4) = "V3" For I = 1 To colI.Count With colI(I) vRes(I, 1) = .Name vRes(I, 2) = .V1 vRes(I, 3) = .V2 vRes(I, 4) = .V3 End With Next I 'Note different file name Set TS = FSO.CreateTextFile(Left(FN, Len(FN) - 4) & "MOD.csv", True) For I = 0 To UBound(vRes) V = Empty ReDim V(1 To 4) For J = 1 To 4 V(J) = vRes(I, J) Next J TS.WriteLine Join(V, ",") Next I TS.Close Set FSO = Nothing End Sub