2013-10-16 8 views
5

Wie kann ich generell zwei 2d Arrays kombinieren?Concat 2D Arrays in f #

Meine Vermutung (ich konnte offensichtlich diese einfach testen) ist, dass sie immer die gleiche Anzahl von Spalten haben:

let concatArrays (arr1:obj[,]) (arr2:obj[,]) = 
    ([arr1; arr2]) |> Array2d.concat 

Diese sieht nicht Funktion existieren though. Nur um klar zu sein, sollte das Ergebnis ein 2D-Array mit der Länge = Summe der Längen und der gleichen Anzahl von Spalten wie das ursprüngliche Array2D erzeugen und sollte der gleiche Typ wie die Eingabe sein, hier obj [,]. Ich könnte das natürlich in einem Looping-Konstrukt machen, aber ich habe mich über einen Weg nach vorne gewundert. Vielen Dank.

Ich habe versucht, dieses:

let append2D (arr1:float[,]) (arr2:float[,]) = 
    let cls = arr1.GetLength 1 
    let rows1 = arr1.GetLength 0 
    let rows2 = arr2.GetLength 0 
    Array2D.init (rows1+rows2) cls (fun i j -> match i with | a when a <= rows1 -> arr1.[i,j] | _ -> arr2.[i,j]) 

Aber das mit dem Index außerhalb der Grenzen Fehler kommt zurück.

Update der letzten Zeile:

Array2D.init (rows1+rows2) cls (fun i j -> if i < rows1 then arr1.[i,j] else arr2.[i,j]) 

Update-Arbeitslösung:

Array2D.init (rows1+rows2) cls (fun i j -> if i < rows1 then arr1.[i,j] else arr2.[i-rows1,j]) 

Dank alle

+1

[Diese] (http://stackoverflow.com/a/2367927/969613) kann helfen – JMK

+0

Danke.Aber verbindet das nicht mehrere 1d Arrays zu einem 2d Array? was ich tun möchte, ist mehrere 2d-Arrays in ein 2d-Array zu verbinden. Aber vielleicht ein guter Ausgangspunkt. Oder bekomme ich es nicht? – nik

+1

Wenn ich Sie richtig verstehe, können Sie einfach 'Array.append' verwenden. Wenn ich falsch liege, werden Sie bitte ein Beispiel für die Eingabe und Ausgabe geben. – Tobber

Antwort

6

dieser Folgende recommendation hier ist eine concat Funktion für zwei gleiche Argumente Spaltengröße Array2D von jedem Typ 'a:

let concat (a1: 'a[,]) (a2: 'a[,]) = 
    let a1l1,a1l2,a2l1,a2l2 = (Array2D.length1 a1),(Array2D.length2 a1),(Array2D.length1 a2),(Array2D.length2 a2) 
    if a1l2 <> a2l2 then failwith "arrays have different column sizes" 
    let result = Array2D.zeroCreate (a1l1 + a2l1) a1l2 
    Array2D.blit a1 0 0 result 0 0 a1l1 a1l2 
    Array2D.blit a2 0 0 result a1l1 0 a2l1 a2l2 
    result 

können Sie diese experimentell überprüfen, aber es wäre mal eine bessere Leistung haben, als jede Variante basiert auf Array2D.init weil Array2D.zeroCreate und Array2D.blit Implementierungen hoch optimiert sind.

1

@Gene hat eine ausgezeichnete Lösung zur Verfügung gestellt, die eingebaute Blit-Funktion scheint hier sehr nützlich zu sein.

Ich möchte meine Nutzung seiner Funktion als Erweiterung der Module Array und Array2D für diejenigen schreiben, die es nützlich finden könnten:

module Array = 
    let first (arr: 'a array) = arr.[0] 
    let others (arr: 'a array) = arr.[1..] 
    let split arr = first arr, others arr 

module Array2D = 
    let joinByRows (a1: 'a[,]) (a2: 'a[,]) = 
     let a1l1,a1l2,a2l1,a2l2 = (Array2D.length1 a1),(Array2D.length2 a1),(Array2D.length1 a2),(Array2D.length2 a2) 
     if a1l2 <> a2l2 then failwith "arrays have different column sizes" 
     let result = Array2D.zeroCreate (a1l1 + a2l1) a1l2 
     Array2D.blit a1 0 0 result 0 0 a1l1 a1l2 
     Array2D.blit a2 0 0 result a1l1 0 a2l1 a2l2 
     result 

    let joinByCols (a1: 'a[,]) (a2: 'a[,]) = 
     let a1l1,a1l2,a2l1,a2l2 = (Array2D.length1 a1),(Array2D.length2 a1),(Array2D.length1 a2),(Array2D.length2 a2) 
     if a1l1 <> a2l1 then failwith "arrays have different row sizes" 
     let result = Array2D.zeroCreate a1l1 (a1l2 + a2l2) 
     Array2D.blit a1 0 0 result 0 0 a1l1 a1l2 
     Array2D.blit a2 0 0 result 0 a1l2 a2l1 a2l2 
     result 

    // here joiner function must be Array2D.joinByRows or Array2D.joinByCols 
    let joinMany joiner (a: seq<'a[,]>) = 
     let arrays = a |> Array.ofSeq 
     if Array.length arrays = 0 then 
      failwith "no arrays" 
     elif Array.length arrays = 1 then 
      Array.first arrays 
     else 
      let rec doJoin acc arrays = 
       if Array.length arrays = 0 then 
        acc 
       elif Array.length arrays = 1 then 
        joiner acc (Array.first arrays) 
       else 
        let acc = joiner acc (Array.first arrays) 
        doJoin acc (Array.others arrays) 
      doJoin <|| Array.split arrays 
      // or doJoin arrays.[0] arrays.[1..] 
0

@Rustam, vielen Dank dafür. Ich brauchte diese Funktionen für die Arbeit mit Excel-Bereichen. Nachdem ich diese Funktionen benutzt habe, habe ich einige Verbesserungsplätze gefunden.

Erstens, anstatt angenommen, dass a1 und a2 Zero-basierte Indizes haben, empfehle ich die Verwendung der Array2D.base1 und Array2D.base2 für Ihre Indizes in den Array2D.blit Funktionen. Beachte, ich brauchte ungefähr 4 Stunden, um mir die Haare auszuziehen, um herauszufinden, dass dies einige Probleme in meinem Code verursacht hat.

dh für die joinByRows Funktion:

let joinMany joiner (a: seq<'a[,]>) = 
     Seq.fold joiner (Seq.head a) (Seq.tail a) 

ich nicht die Leistung überprüfen, aber ich könnte mir vorstellen, dass die eingebaute:

Array2D.blit a1 (Array2D.base1 a1) (Array2D.base2 a1) result 0 0 a1l1 a1l2 
Array2D.blit a2 (Array2D.base1 a2) (Array2D.base2 a2) result a1l1 0 a2l1 a2l2 

Zweitens können Sie Ihre joinMany Funktion erheblich durch die Verwendung Seq.fold vereinfacht werden in Funktion wäre mehr optimiert.