2

Visual Studio 2010 で Excel 相互運用機能を使用して、これらすべてのデータ行をアルファベット順に並べ替えようとしています。一部はすでにアルファベット順に並んでいます。

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();;

しかし、型に問題があります。quit コマンドの前の最終行

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

インテリセンスによって赤い下線が引かれ、私が得るエラーは

「この式は型 seq -> 'a を持つことが期待されていますが、ここには型 unit があります」.

VSが何を伝えようとしているのかはわかりますが、これを修正するために何度か試みましたが、型の問題を回避できないようです。

出力が出力シートに書き込まれるように、パイプラインを正しいタイプにする方法を教えてください。

編集1:これは、次のようにコメントアウトされたソート済み変数で表示される完全なエラーメッセージです

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

エラー メッセージは次のとおりです。

System.Runtime.InteropServices.COMException (0x800A03EC): HRESULT からの例外: Microsoft.Office.Interop.Excel.Range の System.RuntimeType.ForwardCallToInvokeMember (String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData) での 0x800A03EC .get_Item(Object RowIndex, Object ColumnIndex) at FSI_0122.toSeq@34-47.Invoke(Int32 c) in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:line 36 at Microsoft.FSharp. Collections.IEnumerator.map@109.DoMoveNext(b&) Microsoft.FSharp.Collections.IEnumerator.MapEnumerator 1.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeOuter@651[T,TResult](ConcatEnumerator2 x、ユニット unitVar0) Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers.takeInner@644[T,TResult](ConcatEnumerator 2 x, Unit unitVar0) at <StartupCode$FSharp-Core>.$Seq.MoveNextImpl@751.GenerateNext(IEnumerable1&次) Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase で1.MoveNextImpl() at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable 1 source) at Microsoft.FSharp.Collections.ArrayModule.OfSeq[T](IEnumerable1 source) at .$FSI_0122.main@() in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:42行目 エラーのため停止しました

編集 2: この問題は、シート全体をシーケンスに変換するように設計された toSeq 関数が原因でしょうか? 適用する場所は、1行だけに適用したいです。

toSeq の r 変数を 1 に制限しようとしましたが、これは役に立ちませんでした。

私の実際のデータがギザギザの配列であるという事実は重要ですか? 各行に常に 3 つのエントリがあるわけではなく、1 ~ 4 の間で変化します。

編集3:

トーマスの提案に基づいた、私のコードの現在の反復は次のとおりです

#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 e.g. "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

しかし、実際のデータには各行に可変数のエントリがあるため、標準範囲例外エラーが発生しています (これは、少なくとも過去数日間の HRESULT 例外エラーの改善です)。

したがって、個々の行ごとに列を定義するか、行の長さを for ループの変数にバインドする必要があります。(私は推測します)。

4

1 に答える 1

4

|>行末に追加の演算子があるようですSeq.sort-これは、リストがソートされ、コンパイラが代入を実行する式にそれを渡そうとすることを意味します(これはパラメーターをとらず、型を持っています) unit)。

このようなものをコンパイルする必要があります (他の実行時の問題があるかもしれませんが):

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コードがコピーを作成するため (そして、私のバージョンでは、それを新しい変数に割り当てるため)、可変としてマークする必要がないことに注意してくださいsorted

また、並べ替えたシーケンスを配列に変換するためにも使用Array.ofSeqします。これは、Excel の相互運用性が配列の方が優れていると思うからです。

範囲にプロパティを設定する場合Value2、範囲のサイズは、割り当てる配列のサイズと同じにする必要があります。また、設定したい範囲によっては、2D 配列が必要になる場合があります。

EDITランタイムエラーに関しては、コードの何が問題なのか完全にはわかりませんが、ソートを行う方法は次のとおりです(文字列値を持つ列が1つしかなく、行をソートしたい場合):

// Get the row count and calculate the name of the last cell e.g. "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
于 2013-03-05T13:07:14.870 に答える