J'utilise Excel interop dans Visual Studio 2010 pour essayer de trier toutes ces lignes de données par ordre alphabétique. Certains sont déjà dans l'ordre alphabétique. La version actuelle de mon code est la suivante (je commence à utiliser mon code interactif avant de le placer dans un fichier fs).Tri des lignes Excel par ordre alphabétique dans F # (Office.Interop)
#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();;
Mais il y a un problème avec les types. La dernière ligne avant la quit
(outSheet.Cells.Rows.[i] :?> Range).Value2 <- row.Value2;;
est rouge soulignée par IntelliSense et l'erreur que je reçois est
« Cette expression devrait avoir le type suivants -> « a, mais ici est de type unit ». Je comprends ce que VS essaie de me dire, mais j'ai essayé plusieurs fois de résoudre ce problème maintenant et je n'arrive pas à contourner le problème du type.
Quelqu'un peut-il s'il vous plaît aviser comment je peux obtenir le pipeline au bon type afin que la sortie écrira à ma feuille de sortie?
EDIT 1: Ceci est le message d'erreur complet que je reçois avec la variable triée a commenté comme suit
let sorted = row |> toSeq //|> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort
Le message d'erreur est le suivant: -
System.Runtime.InteropServices.COMException (0x800A03EC): Exception from HRESULT: 0x800A03EC at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData) at Microsoft.Office.Interop.Excel.Range.get_Item(Object RowIndex, Object ColumnIndex) at [email protected](Int32 c) in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:line 36 at [email protected](b&) at Microsoft.FSharp.Collections.IEnumerator.MapEnumerator
1.System-Collections-IEnumerator-MoveNext() at [email protected]651[T,TResult](ConcatEnumerator
2 x, Unit unitVar0) at [email protected]644[T,TResult](ConcatEnumerator2 x, Unit unitVar0) at <StartupCode$FSharp-Core>[email protected](IEnumerable
1& next) at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase1.MoveNextImpl() at Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase
1.System-Collections-IEnumerator-MoveNext() at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable1 source) at Microsoft.FSharp.Collections.ArrayModule.OfSeq[T](IEnumerable
1 source) at [email protected]() in C:\Users\Simon Hayward\Dropbox\F# Scripts\TotalJobsSort\sortExcelScript.fsx:line 42 Stopped due to error
EDIT 2: Serait-ce problème est-ce dû au fait que la fonction toSeq est conçue pour transformer une feuille entière en séquence? Lorsque je l'applique, je veux seulement qu'il s'applique à une rangée.
J'ai essayé de limiter la variable r à toSeq à 1, mais cela n'a pas aidé.
Est-ce que le fait que mes données réelles sont en dents de scie? Il n'a pas toujours 3 entrées dans chaque rangée, il varie entre 1 et 4.
EDIT 3:
Voici l'itération actuelle de mon code, basé sur les suggestions de Tomas
#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
Mais parce que les données réelles ont un nombre variable d'entrées dans chaque rangée j'obtiens l'erreur d'exception de gamme standard (c'est une amélioration sur les erreurs d'exception HRESULT des derniers jours au moins).
Je dois donc définir des colonnes pour chaque ligne individuelle, ou simplement lier la longueur de la ligne à une variable de la boucle for. (Je dirais).
pour noter: Si je commente sur cette ligne et à la place imprimer à la console: ligne |> toSeq |> Seq.map (fun x -> x.Value2.ToString()) |> Seq.sort |> printf "% A" ;; Je reçois l'erreur suivante pour chaque ligne: - Erreur: Exception de HRESULT: 0x800A03EC qui est une erreur de plage pour Excel. Alors peut-être que la faute est dans l'énumération dans la fonction toSeq ?? –