> 90 degrés - Retrouvez les réponses et les commentaires concernant cette question" />
8
votes

"Tourner" un iNeumable > 90 degrés

Ce que je recherche, c'est une opération de base (laquelle je suis sûr d'avoir un nom que je n'augs tout simplement pas le guichet automatique). J'ai une matrice comme:

{1,2,3}

{A, N, F}

{7,8,9}

Que je voudrais muter dans

{1, a, 7}

{2, n, 8}

{3, F, 9 }

(Les identifiants ci-dessus ne sont que des identifiants pour les objets non réels. Les objets réels sont du même type et non-commandé)

Je préférerais une solution déclarative à elle mais la vitesse est un facteur. Je vais devoir tourner assez de tables (cellules 100k une min) et une version lente serait sur le chemin critique.

Cependant, je suis toujours plus intéressé par une solution lisible. Je cherche des solutions alternatives au ci-dessous. (Par alternative, je ne veux pas dire des variations, mais une approche différente) xxx

parmi deux solutions presque aussi lisibles que j'aurai plus vite mais la lisibilité passe avant la vitesse

edit Ce sera toujours une matrice carrée


6 commentaires

C'est ce qu'on appelle la transposition ( en.wikipedia.org/wiki/transpose )


Je ne pense pas que cela puisse devenir plus lisible que cela!


Est-ce seulement pour les matrices carrées, ou aussi pour non carrée?


@Novox thx je savais qu'il y avait quelque chose que mon algèbre que j'étais oublié


Une rotation supérieure à 90 degrés dans le sens des aiguilles d'une montre donnait en effet {7, a, 1} {8, n, 2} {9, f, 3} .


@Msalters Vous avez raison et je suis sûr que c'est toujours évident ce que j'avais réellement besoin si le "virage 90 degrés" n'est pas précis


6 Réponses :



1
votes

Votre question semble impliquer que vous souhaitez modifier la matrice d'origine.

Si c'est le cas, et si vous êtes capable de stocker la matrice sous forme de IList > Matrix , cela fonctionnera cependant, cependant, uniquement dans le cas d'une matrice carrée. xxx


1 commentaires

C'est une version spécifique de l'approche dans la question qui s'appuie sur ilon >. Je cherche une approche différente s'appuyant sur iEnumerable >



11
votes

Je suis un peu si de cette mise en œuvre. Il a des effets secondaires locaux à l'itérateur mais je suis logiquement propre à moi. Cela suppose que chaque séquence est la même longueur mais devrait fonctionner pour tout. Vous pouvez y penser comme une longueur variable zip () méthode. Il devrait fonctionner mieux que les autres solutions Linq liées trouvées dans les autres réponses, car elle n'utilise que les opérations minimales nécessaires au fonctionnement. Probablement encore mieux sans l'utilisation de Linq. Pourrait même être considéré comme optimal. xxx


8 commentaires

Cela me semble propre. Il sera exécuté avec impatience aussi loin que je peux voir. Pas un problème dans mon cas depuis que je devrai toujours introduire tout. La mise en œuvre de la méthode pourrait être à lire si le côté des appels sera facile.


@Rune: De quoi s'agit-il de cela qui pourrait être difficile à lire? C'est une implémentation assez simple dans l'IMHO.


Sur une note latérale, le deuxième appel à toarray () pourrait probablement être supprimé. Ainsi, un plus si vous avez de nombreuses séquences à ziptuer.


énumérateurs.Tous (x => x.movenext ()) ne suit pas vraiment "la moins surprise" puisque l'instruction LINQ habituelle est sans effet secondaire


En fait, vous n'avez pas besoin de TOARRAY, cela fonctionnera sans et si vous déplacez tout à l'exception de la première ligne dans une méthode différente, il s'agit également d'une évaluation paresseuse comme la plupart des méthodes LINQ. Si vous n'aviez pas déjà reçu les points au moins un +1 pour vous souvenir de disposer :)


@Rune: À la deuxième pensée, pour une mise en œuvre générale (ce que je visitant), il doit rester. Il pourrait être possible d'accéder aux lignes hors de commande qui entraînent une énumération dans l'ordre. Cependant, dans votre cas, je suppose que vous allez y accéder séquentiellement, donc ce n'est peut-être pas un problème pour vous.


Oh mec, je viens de trouver un très similaire Mise en œuvre < / a> de transpose () sur un Question non liée . C'est Eerie.


Pour une mise en œuvre générale, cela nécessite un chèque que l'extérieur IEnumerable n'est pas vide. Sinon, la boucle tandis que la boucle fonctionne pour toujours (énumérable.all () est vrai pour vide) et donne des tableaux vides indéfiniment.



0
votes

Eh bien, ce que vous recherchez ici est une transformation t [] [] -> t [] [] . Il y a beaucoup de ienumerabe >. Transpose () Solutions autour, mais ils bouchent tous pour boucler des énumérables à l'aide de recherches / clés temporaires et laissent beaucoup à désirer quand il s'agit de la performance sur un énorme volume. Votre exemple fonctionne réellement plus vite (bien que vous puissiez perdre la deuxième portée).

Première demande "Dois-je besoin de Linq du tout". Vous n'avez pas décrit ce que le but de la matrice transposée sera et si la vitesse est bien votre préoccupation, vous risquez de bien rester à l'écart de la Linq / Foreach et de le faire à l'ancienne (pour l'intérieur pour)


1 commentaires

Non, je n'ai pas besoin Linq, c'est pourquoi j'ai demandé une solution déclarative par opposition à une solution LINQ :). Il y a de la place pour améliorer la lisibilité avec des performances excessives, mais l'amélioration aveugle de la lisibilité peut avoir une incidence sur nos performances. C'est sur le chemin critique



0
votes

Voici le mien si quelqu'un est intéressé. Il fonctionne de la même manière que Jeff's, mais semble être légèrement plus rapide (en supposant que ces toarrayses () sont nécessaires). Il n'y a pas de boucles ou de temporaires visibles, et il est beaucoup plus compact:

public static IEnumerable<IEnumerable<T>> Transpose<T>(
    this IEnumerable<IEnumerable<T>> source)
{
    return source
        .Select(a => a.Select(b => Enumerable.Repeat(b, 1)))
        .DefaultIfEmpty(Enumerable.Empty<IEnumerable<T>>())
        .Aggregate(Zip);
}

public static IEnumerable<IEnumerable<T>> Zip<T>(
    IEnumerable<IEnumerable<T>> first, 
    IEnumerable<IEnumerable<T>> second)
{
    var firstEnum = first.GetEnumerator();
    var secondEnum = second.GetEnumerator();

    while (firstEnum.MoveNext())
        yield return ZipHelper(firstEnum.Current, secondEnum);
}

private static IEnumerable<T> ZipHelper<T>(
    IEnumerable<T> firstEnumValue, 
    IEnumerator<IEnumerable<T>> secondEnum)
{
    foreach (var item in firstEnumValue)
        yield return item;

    secondEnum.MoveNext();

    foreach (var item in secondEnum.Current)
        yield return item;
}


0 commentaires

0
votes

Voici ma solution basée sur l'énumérateur, qui tente d'utiliser pour pour gagner la vitesse sur foreach / linq: xxx


0 commentaires