在F#中按字母顺序排列Excel行(Office.Interop)

我正在使用Visual Studio 2010中的Excel互操作来尝试按字母顺序对所有这些数据行进行sorting。 有些已经按字母顺序排列。

Accountancy Graduate, Trainees Banking, Insurance, Finance Accountancy Graduate, Trainees Customer Services Accountancy Graduate, Trainees Education Accountancy Graduate, Trainees Health, Nursing Accountancy Graduate, Trainees Legal Accountancy Graduate, Trainees Management Consultancy Accountancy Graduate, Trainees Media, New Media, Creative Accountancy Graduate, Trainees Oil, Gas, Alternative Energy Accountancy Graduate, Trainees Public Sector & Services Accountancy Graduate, Trainees Recruitment Sales Accountancy Graduate, Trainees Secretarial, PAs, Administration Accountancy Graduate, Trainees Telecommunications Accountancy Graduate, Trainees Transport, Logistics 

我的代码的当前版本如下(我得到我的代码工作在交互之前,把它放入一个FS文件)。

 #r "office.dll" #r "Microsoft.Office.Interop.Excel.dll" open System;; open System.IO;; open Microsoft.Office.Interop.Excel;; let app = new ApplicationClass(Visible = true) let inputBook = app.Workbooks.Open @"C:\Users\simon.hayward\Dropbox\F# Scripts\TotalJobsSort\SortData.xlsx" //work //let inputBook = app.Workbooks.Open @"C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\SortData.xlsx" //home let outputBook = app.Workbooks.Add() let inSheet = inputBook.Worksheets.[1] :?> _Worksheet let outSheet = outputBook.Worksheets.[1] :?> _Worksheet let rows = inSheet.UsedRange.Rows.Count;; let toSeq (range : Range) = seq { for r in 1 .. range.Rows.Count do for c in 1 .. range.Columns.Count do let cell = range.Item(r, c) :?> Range yield cell } for i in 1 .. rows do let mutable row = inSheet.Cells.Rows.[i] :?> Range row |> toSeq |> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort |> (outSheet.Cells.Rows.[i] :?> Range).Value2 <- row.Value2;; app.Quit();; 

但是types有问题。 quit命令之前的最后一行

 (outSheet.Cells.Rows.[i] :?> Range).Value2 <- row.Value2;; 

红色是由intellisense加下划线,我得到的错误是

“这个expression式预计会有typesseq – >'a,但这里有types单位”。

我得到了什么VS想告诉我,但我已经做了几个尝试,现在解决这个问题,我似乎无法解决types问题。

任何人都可以请告诉我如何获得pipe道到正确的types,以便输出将写入我的输出表?

编辑1:这是完整的错误消息,我得到的sortingvariables注释如下

 let sorted = row |> toSeq //|> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort 

错误信息是: –

System.Runtime.InteropServices.COMException(0x800A03EC):从Microsoft.Office.Interop.Excel.Range System.RuntimeType.ForwardCallToInvokeMember(stringmemberName,BindingFlags标志,对象目标,Int32 [] aWrapperTypes,MessageData&msgData)HRESULT:0x800A03ECexception调用(Int32 c)在C:\ Users \ Simon Hayward \ Dropbox \ F#Scripts \ TotalJobsSort \ sortExcelScript.fsx:Microsoft.FSharp上的第36行。 Collections.IEnumerator.map@109.DoMoveNext(b&)at Microsoft.FSharp.Collections.IEnumerator.MapEnumerator 1.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeOuter@651[T,TResult](ConcatEnumerator 2 x,Unit unitVar0)at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeInner@644 [T,TResult](ConcatEnumerator 2 x, Unit unitVar0) at <StartupCode$FSharp-Core>.$Seq.MoveNextImpl@751.GenerateNext(IEnumerable 1&next)在Microsoft.FSharp.Core.CompilerServices.GeneratedSeq 1.MoveNextImpl() at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase上的Microsoft.FSharp.Collections.SeqModule.ToArray [T](IEnumerable 1 source) at Microsoft.FSharp.Collections.ArrayModule.OfSeq[T](IEnumerable 1.System-Collections-IEnumerator-MoveNext()上的uenceBase 1.MoveNextImpl() at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase C:\ Users \ Simon Hayward \ Dropbox \ F#Scripts \ TotalJobsSort \ sortExcelScript.fsx:第42行由于错误而停止

编辑2:这个问题可能是由于toSeq函数被devise为将整个工作表变成一个序列? 我在哪里申请,我只希望它适用于一行。

我试图限制在seSeq的rvariables为1,但这并没有帮助。

我的实际数据是一个锯齿状的数组事实吗? 它并不总是每行有3个条目,它在1和4之间变化。

编辑3:

基于Tomas的build议,下面是我的代码的当前迭代

 #r "office.dll" #r "Microsoft.Office.Interop.Excel.dll" open System;; open System.IO;; open Microsoft.Office.Interop.Excel;; let app = new ApplicationClass(Visible = true);; let inputBook = app.Workbooks.Open @"SortData.xlsx" //workbook let outputBook = app.Workbooks.Add();; let inSheet = inputBook.Worksheets.[1] :?> _Worksheet let outSheet = outputBook.Worksheets.[1] :?> _Worksheet let rows = inSheet.UsedRange.Rows.Count;; let columns = inSheet.UsedRange.Columns.Count;; // Get the row count and calculate the name of the last cell eg "A13" let rangeEnd = sprintf "A%d" columns // Get values in the range A1:A13 as 2D object array of size 13x1 let values = inSheet.Range("A1", rangeEnd).Value2 :?> obj[,] // Read values from the first (and only) column into 1D string array let data = [| for i in 1 .. columns -> values.[1, i] :?> string |] // Sort the array and get a new sorted 1D array let sorted1D = data |> Array.sort // Turn the 1D array into 2D array (13x1), so that we can write it back let sorted2D = Array2D.init 1 columns (fun i _ -> data.[i]) // Write the data to the output sheet in Excel outSheet.Range("A1", rangeEnd).Value2 <- sorted2D 

但是,因为实际数据在每一行中都有可变数量的条目,所以我得到了标准范围exception错误(至less在最近几天的HRESULTexception错误上有所改进)。

所以我需要为每个单独的行定义列,或者只是将行的长度绑定到for循环中的variables。 (我猜)。

看起来你在Seq.sort的末尾添加了一个额外的|>运算符 – 这意味着列表被sorting,然后编译器会尝试将它传递给执行赋值的expression式(它不会执行任何操作参数和typesunit )。

像这样的东西应该编译(虽然可能有一些其他运行时问题):

 for i in 1 .. rows do let row = inSheet.Cells.Rows.[i] :?> Range let sorted = row |> toSeq |> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort (outSheet.Cells.Rows.[i] :?> Range).Value2 <- Array.ofSeq sorted 

请注意,您不需要将row标记为可变,因为代码会创build一个副本(并且 – 在我的版本中 – 将其分配给一个新的variablessorted )。

我也使用Array.ofSeq将已sorting的序列转换为数组,因为我认为Excel interop可以更好地处理数组。

在范围上设置Value2属性时,范围的大小应该与您分配给它的数组的大小相同。 另外,根据你想设置的范围,你可能需要一个二维数组。

编辑关于运行时错误,我不完全确定你的代码有什么问题,但这里是我将如何做sorting(假设你只有一个string值的列,你想sorting的行):

 // Get the row count and calculate the name of the last cell eg "A13" let rows = inSheet.UsedRange.Rows.Count let rangeEnd = sprintf "A%d" rows // Get values in the range A1:A13 as 2D object array of size 13x1 let values = inSheet.Range("A1", rangeEnd).Value2 :?> obj[,] // Read values from the first (and only) column into 1D string array let data = [| for i in 1 .. rows -> values.[i, 1] :?> string |] // Sort the array and get a new sorted 1D array let sorted1D = data |> Array.sort // Turn the 1D array into 2D array (13x1), so that we can write it back let sorted2D = Array2D.init rows 1 (fun i _ -> data.[i]) // Write the data to the output sheet in Excel outSheet.Range("A1", rangeEnd).Value2 <- sorted