J'ai un tableau plat comme celui-ci et un autre tableau plat qui décrit les dimensions:
case class Elem(elem: Array[Elem])
Alors maintenant, je dois être capable de l'aplatir et de renvoyer un tableau 2 * 2 comme celui-ci:
val unflattened = {{0,1},{2,3}}
Les dimensions peuvent être de n'importe quel ordre. La seule condition est que la longueur du tableau plat soit égale au produit des dimensions. Par exemple, si les dimensions sont
Tableau (3,3)
alors je suppose que le tableau plat elems devra avoir 9 éléments dedans! Les conditions préalables seront vérifiées ailleurs donc je n'ai pas à m'en soucier ici! Tout ce que j'ai à faire est de renvoyer un tableau non aplati.
Comme cela doit fonctionner sur n'importe quelle taille de dimension, je pense que je dois probablement définir une structure récursive pour mettre mes résultats! Quelque chose comme ça?
val elems = Array(0,1,2,3) val dimensions = Array(2,2)
Cela pourrait-il fonctionner?
Avez-vous une idée de la façon de mettre en œuvre cette fonction?
3 Réponses :
Il existe une fonction groupée
sur les tableaux qui fait ce que vous voulez.
@ Array(0,1,2,3).grouped(2).toArray res2: Array[Array[Int]] = Array(Array(0, 1), Array(2, 3))
Mais cela ne fonctionnera pas pour un certain nombre de dimensions, n'est-ce pas?
Voici une solution:
trait Matrix case class SimpleMatrix(rows: Vector[Int]) extends Matrix case class HigherMatrix(matrices: Vector[Matrix]) extends Matrix def unflatten(flat: Vector[Int], dims: Vector[Int]): Matrix = if (dims.length <= 1) { SimpleMatrix(flat) } else { val (Vector(dim), rest) = dims.splitAt(1) val subs = flat.grouped(flat.length/dim).map(a => unflatten(a, rest)).toVector HigherMatrix(subs) }
J'ai utilisé Vector
car Array
n'est pas vraiment un type Scala et ne le fait pas autorise la conversion de Array [Int]
vers Array[Any
.
Notez que cela implémente une seule des partitions possibles avec les dimensions données, donc cela peut ou non être ce qui est requis.
Ceci est une version utilisant des types basés sur le trait Matrix
dans une autre réponse:
def unflatten(flat: Vector[Any], dims: Vector[Int]): Vector[Any] = if (dims.length <= 1) { flat } else { val (Vector(dim), rest) = dims.splitAt(1) flat.grouped(flat.length/dim).map(a => unflatten(a, rest)).toVector }
Bien que vous devriez pouvoir le faire avec une structure récursive simple, j'ai choisi une structure plus adaptée au problème.
val sm_2__2_2 = arrayToSquareMatrix(Range.inclusive(1, 4).toList, 2, 2) // sm_2__2_2: Matrix = SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4)))) val m_2__3_2 = arrayToMatrix(Range.inclusive(1, 6).toList, 2, List(3, 2)) // m_2__3_2: Matrix = SimpleMatrix(List(Row(List(1, 2, 3)), Row(List(4, 5, 6)))) val sm_3__2_2_2 = arrayToSquareMatrix(Range.inclusive(1, 8).toList, 3, 2) // sm_3__2_2_2: Matrix = HigherMatrix(List(SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4)))), SimpleMatrix(List(Row(List(5, 6)), Row(List(7, 8)))))) val m_3__3_2_2 = arrayToMatrix(Range.inclusive(1, 12).toList, 3, List(3, 2, 2)) // m_3__3_2_2: Matrix = HigherMatrix(List(SimpleMatrix(List(Row(List(1, 2)), Row(List(3, 4)))), SimpleMatrix(List(Row(List(5, 6)), Row(List(7, 8)))), SimpleMatrix(List(Row(List(9, 10)), Row(List(11, 12))))))
Voici les exemples
case class Row(elems: List[Int]) trait Matrix case class SimpleMatrix(rows: List[Row]) extends Matrix case class HigherMatrix(matrices: List[Matrix]) extends Matrix // since your flat arrays are always of proper sizes... we are not handling error cases // so we are dealing with higher N-dimension matrices with size List(s1, s2, ...,sN) // I have chosen List for the example (as its easy to print), you should choose Array def arrayToMatrix(flat: List[Int], dimension: Int, sizes: List[Int]): Matrix = dimension match { case 1 | 2 => // since your flat arrays are always of proper sizes... there should not be any problems here SimpleMatrix( flat .grouped(sizes.head) .map(Row) .toList ) case _ => HigherMatrix( flat .grouped(sizes.tail.reduce(_ * _)) .map(g => arrayToMatrix(g, dimension - 1, sizes.tail)) .toList ) } def arrayToSquareMatrix(flat: List[Int], dimension: Int, size: Int): Matrix = arrayToMatrix(flat, dimension, Range.inclusive(1, dimension).map(_ => size).toList)
La question n'est pas claire, mais l'idée est de permettre une taille différente dans chaque dimension et non une taille unique dans toutes les dimensions.
@Tim même si cela est nécessaire ... nous pouvons facilement modifier cela pour correspondre à cela.
@Tim Mis à jour pour inclure toutes les tailles dans d'autres dimensions.
Quel est le val sm_3__2? Quelle est sa dimension? Pour moi, c'est une matrice 3x2, ce qui signifie qu'elle devrait avoir 6 éléments au total dans la structure plate, mais votre échantillon a 8 éléments. Cela devrait donc produire une matrice de 3 lignes et 2 colonnes, mais vous avez un résultat de 4 lignes et 2 colonnes. Ce n'est pas correct!
sm_3__2
est une matrice carrée (cube pour être plus précis) 3-dimensionnelle
avec des tailles 2 * 2 * 2
, donc elle aura 8 éléments
. Et m_3__3_2_2
est une matrice tridimensionnelle
non carrée avec des tailles 3 * 2 * 2
donc elle a 12
éléments. Et oui, il y a un problème, le résoudre.
Voici quelque chose de similaire qui a exactement ce que je veux: deeplearning4j.org/docs/latest/nd4j -matrix-manipulation Le premier exemple où une matrice est créée puis transposée est exactement ce dont j'ai besoin!
Voici la méthode de remodelage qui fait exactement ce que je veux: deeplearning4j.org/docs/latest / nd4j-matrice-manipulation
Corrigé. Fonctionne comme prévu maintenant.
Pouvez-vous également corriger / modifier l'exemple sm_3__2? Je n'ai toujours pas tort! Peut-être avez-vous oublié de le modifier!
L'argument dimension
semble dupliquer la longueur de la liste tailles
.
J'ai ajouté une nouvelle version à ma réponse en utilisant des types inspirés du trait Matrix
dans cette réponse, si l'utilisation de Any
n'est pas acceptable.
sm_3__2
est correct. c'est une matrice 2 * 2 * 2 signifiant une HigherMatrix contenant 2 SimpleMatrix de 2 * 2.
Changement des noms de variable pour éviter toute confusion.
Vous devez réfléchir à la manière dont les résultats de cette opération seront utilisés. Cela aidera à clarifier le type de résultat souhaité, ce qui, à son tour, aidera à clarifier l'algorithme que vous devez utiliser pour obtenir ce résultat.
Les résultats seront ultérieurement interprétés par un autre programme. Cette fonction doit simplement prendre ces 2 paramètres et récupérer le résultat comme dimensionnalité appropriée!
Alors, quel est le format des «résultats» qui sont interprétés par l'autre programme? Comment «la dimensionnalité appropriée» est-elle exprimée dans le fichier de données?
Je comprends ce que tu veux dire. Je pourrais renvoyer un objet ou un type Any et c'est à l'appelant d'obtenir le type approprié. Je pourrais également renvoyer des informations telles que le type de retour est un tableau et si oui, combien de dimensions!
Pourriez-vous avoir plus de tableaux à deux dimensions?
@sparkr Quelle sortie attendez-vous si la dimension est Array (2,3)?
Voulez-vous dire un vrai tableau 3D "3 dimensions", un tableau 4D? Similaire à ce que nous avons dans les problèmes de réduction dimensionnelle?
Oui, je pourrais avoir n'importe quelle dimensionnalité!
Donc, pour une dimension de tableau (2,3), j'attends un tableau à 2 dimensions avec 2 lignes et 3 colonnes. Le tableau plat contiendrait alors un total de 6 éléments!
Pour un vrai tableau 3D, votre tableau plat ne peut pas avoir 9 éléments car le nombre doit être un cube et un carré. L'exemple avec 9 éléments donne l'impression d'être un tableau 2D de taille 3x3. S'il ne s'agit que d'un tableau 2D et que votre tableau plat a toujours la taille attendue, alors vous pouvez simplement faire un
grouped (n)
pour un tableaun * m
.Ok donc pour un tableau 3D, j'aurais les dimensions comme ceci: Array (2,2,2) par exemple!