11
votes

Déplacer () pour insérer / supprimer l'élément (s) d'un tableau dynamique de chaîne

Utilisation de System.Move () Pour insérer / Supprimer l'élément (s) d'un tableau de chaîne n'est pas aussi simple que l'insertion / la supprime à partir d'un autre tableau de types de données simples. Le problème est ... la chaîne est une référence comptée dans Delphi. Utilisation de Move () sur les types de données comptés par référence nécessitent des connaissances plus approfondies sur le comportement du compilateur interne.

Quelqu'un peut-il ici expliquer les étapes nécessaires pour que je puisse réaliser cela, ou mieux avec des codes d'extraits, ou dirigez-moi à une bonne référence sur Internet?

Oh, s'il vous plaît, ne me dis-je pas d'utiliser la "façon paresseuse mais lente", c'est-à-dire pour la boucle, je sais que.


0 commentaires

7 Réponses :


2
votes

Pour insérer une chaîne, ajoutez simplement une chaîne (la méthode paresseuse) à la fin de la matrice (qui est une matrice de pointeurs), puis utilisez déplacer pour modifier l'ordre des éléments. de ce tableau (de pointeurs).


0 commentaires

2
votes

Si je voulais insérer une corde au milieu d'une liste des chaînes, j'utiliserais Tstringlist.insert. (Il utilise-t-il rapidement System.Move.)

Une raison particulière pour laquelle vous utilisez un tableau au lieu d'une TStringList?


12 commentaires

Pour la raison de la performance, car mon tableau serait possible d'être rempli d'énormes objets. Je réalise que Tstringlist.Capacité aidera, mais Tstringlist fera toujours une vérification inutile - selon la documentation-- "... Affectation d'une valeur plus petite que le comptage supprime les chaînes de la fin de la liste. Affectation d'une valeur supérieure à celle des comptes. espace pour plus de strings à ajouter. " Dans mon cas, je n'ai pas besoin d'un tel chèque.


@Phantom: Eh bien, tant que vous mesurez la surcharge réelle de l'approche TStringlist . De nombreuses personnes sont étonnamment tolérantes à des retards de quelques millisecondes.


@Phantom: assez juste, mais il y a d'autres implications de performance à prendre en compte. Par exemple, si vous devez remplir votre matrice avec un grand nombre de chaînes, utilisez-vous setlength (myarray, longueur (myarray) + 1) à chaque fois? C'est un grand nombre de réallocs et de copies, et cela peut vraiment faire glisser la performance. Pour écarter cette question, vous devez allouer plus d'espace que vous utilisez, vous avez donc besoin de quelque chose pour garder une trace de la capacité et du nombre actuel. Pour gérer cela, vous devez l'encapsuler dans un objet ... et ensuite vous êtes bien sur la route pour réinventer la TStringList. : P


Oui, Mason est absolument juste. L'exemple de son commentaire est l'un des problèmes de performance Delphes les plus courants et les plus graves. Mais, @Phantom, puisque vous parlez de déplacer , je suppose que vous êtes déjà au courant de ce problème.


@ Mason, non, je vais allouer une mémoire, il suffit de dire pour 16384 articles et allouera plus de 16384 s'il est apparemment nécessaire.


@ Mason, je n'ai pas l'intention de réinventer Tstringlist. Il y a tellement de fonctionnalités dans Tstringlist que je n'ai pas besoin de travailler dans ce tableau. Pour être honnête, le tableau sera doté de tous les fichiers de tous les disques durs attachés à un ordinateur.


@Phantom: Mais vous avez besoin de réorganiser les éléments du tableau?


@Andreas, non, les articles n'ont pas besoin d'être triés.


AFAIK, car les éléments de suppression ou d'insertion à une matrice ne nécessitent aucun mécanisme de tri / d'indexation.


@Andreas, TStringList Utilisez System.Move () au lieu d'une telle boucle. En ce qui concerne la mise en œuvre de TstringList en un coup d'œil, je ne pouvais pas saisir les conditions réelles pour utiliser le déplacement () sur les types de données comptés de référence. Cependant, il semble que je dois l'étudier plus profondément, ainsi que le commentaire de @ Patrickvl.


@Phantom: TStringList (bien sûr!) Utilise uniquement Déplacer si cela doit modifier l'ordre des chaînes, par exemple, si vous insérez une chaîne au milieu de la Array (pour ensuite toutes les chaînes après la nouvelle insérée, il est nécessaire de descendre dans la matrice). Si vous ajoutez simplement une chaîne au bas de la matrice, aucun Déplacer n'est nécessaire, ni dans un tableau de chaîne ni dans un TStringList !


@Andreas, Oups, j'ai mal compris ce que vous vouliez dire, maintenant je l'attrape. :-)



-1
votes

Si vous utilisez System.Move pour mettre des éléments dans une gamme de chaînes, vous devez savoir que les chaînes qui, avant le déménagement (et maintenant écrasées), avaient un nombre de référence de -1 pour des chaînes constantes, ou > 0 pour les chaînes variables. Les chaînes constantes ne doivent pas être modifiées, mais les chaînes variables doivent être traitées en conséquence: vous devez réduire manuellement leur nombre de référence (avant qu'ils ne soient écrasés!). Pour ce faire, vous devriez essayer quelque chose comme ceci:

Dec(PStrRec(IntPtr(SomeString)-12).refCnt);


5 commentaires

@Patrickvl: Donc, vous me recommandez toujours d'utiliser TStringList même si pour mon cas, c'est-à-dire que la matrice sera remplie de tous les fichiers de tous les disques durs attachés à un ordinateur. Tstringlist sera-t-il assez rapide?


@Phantom: Tstringlist a été conçu pour manipuler un grand nombre de cordes. Si vous avez Delphi, vous avez des cours.Pas; Parcourez le code à Tstringlist et Tstrings et voyez le nombre de bits de code que vous pouvez trouver qui existe spécifiquement pour des raisons de performance. C'est l'une des classes les plus utilisées de l'ensemble du RTL, et il a été essentiellement testé pendant 15 ans maintenant. Vous devriez travailler assez fort pour proposer une solution sensiblement plus rapide que TStringList lors de la manipulation des cordes. Si vous voulez savoir si c'est lent, essayez de l'utiliser et voyez si cela se sent lent ou non.


-1 Pour suggérer une modification manuelle des structures de données internes définies par la mise en œuvre. Vous auriez pu simplement affecter sulsing: = '' et que le compilateur s'occupe de la situation de dénonciation zéro-référence, ainsi que de la sécurité thread-sécurité.


@ROB: Je répondais simplement à la question de Phantom comment réduire le nombre de références manuellement. Je crois que c'est une question valable de répondre - même quand il n'est pas conseillé de le faire! (Est-ce que je n'ai pas mentionné cela dans ma dernière déclaration?) Sûr, régler suls: = '' fonctionne aussi, mais qui repose sur la magie du compilateur, alors ma réponse a une crédibilité, n'est-ce pas pense?


Non, Patrick, la question de pas demande comment réduire le nombre de références d'une chaîne. Phantom a simplement indiqué qu'il savait que le comptage de référence était un problème qui se préoccupe lors de l'utilisation de Move, il a donc demandé comment utiliser le déplacement pour ajuster un éventail de chaînes. Il n'y avait rien à suggérer que la matrice était en réalité une blob de mémoire non typée, il n'y a donc aucune raison de penser que le compilateur Magic n'est pas disponible.



1
votes

appelez unique () dessus, avant de jouer avec elle.

http://docwiki.embarcadero.com/vcl/en/system.uniqueString

Ensuite, vous avez une chaîne avec une seule référence.

Fat Chance que c'est ce que le fait de supprimer et d'insérer aussi, et je doute que vous soyez plus rapide.


2 commentaires

"Fat Chance" signifie que quelque chose est improbable . Par exemple: "Pensez-vous que notre patron va nous donner un bonus cette année?" "Graisse de chance!" Appeler uniquesString est exactement quelle suppression et l'insertion fera pour changer le contenu du caractère d'une chaîne. Il n'est pas nécessaire de l'appeler lors de la modification du contenu de l'élément d'une matrice dynamique, cependant.


Oups, les expressions sont toujours douloureuses dans les langues étrangères :-) Quoi qu'il en soit, j'ai raté le "tableau de" bit. Ensuite, finalisez simplement les bits supprimés et initialiser les bits non supprimés (ou les remplir avec zéro) feraient



22
votes

J'ai démontré comment supprimer des articles d'un tableau dynamique avant:

  • Delphi Q & A: Comment supprimer un élément d'un tableau?

    Dans cet article, je commence par le code suivant: xxx

    vous ne peut pas vous tromper avec ce code. Utilisez quelle valeur pour x vous voulez; Dans votre cas, remplacez-le par chaîne . Si vous souhaitez obtenir plus d'amateur et utiliser déplacer , il y a le chemin à faire cela aussi. xxx

    depuis x x est string , l'appel de finaliser équivaut à l'attribution de la chaîne vide à cet élément de tableau. J'utilise finaliser dans ce code, car il fonctionnera pour tous les types d'éléments de tableau , même des types qui incluent des enregistrements, des interfaces, des chaînes et d'autres tableaux.

    pour l'insertion, vous venez de déplacer des choses la direction opposée: xxx

    Utiliser finaliser quand vous serez sur le point de faire quelque chose qui est à l'extérieur Les limites de la langue, telles que l'utilisation de la procédure MODER NON-SAFE pour écraser une variable d'un type géré par le compilateur. Utilisez initialiser lorsque vous rentrez dans la partie définie de la langue. (La langue définit ce qui se passe lorsqu'un tableau se développe ou rétrécit avec setlength , mais il ne définit pas comment copier ou supprimer des chaînes sans utiliser une déclaration d'affectation de chaîne.) >


4 commentaires

Merci beaucoup. :-) Je vais essayer votre code d'extraction et accepterai cela comme réponse acceptée si cela réussit. Mais je dois aller au bureau maintenant. :-)


Juste une suggestion, ou peut-être une demande, nous serons heureux si vous souhaitez mettre à jour votre article mentionné pour inclure également l'insertion. J'aime votre conception de page Web.


J'ai modifié le code de Rob pour fournir une façon de le faire en utilisant la construction de Tarray plus récente . Que pensez-vous, Rob? Des problèmes que j'ai manqués?


Devrait être: Termings: = Althength - Index - 1; dans deletex ()



0
votes

Voulant simplement ajouter ceci pour des personnes qui viennent ici à l'avenir.

Modification du code de Rob, j'ai proposé cette façon de le faire qui utilise le nouveau TARRAY constructions. xxx

une chose similaire peut être fait pour l'insert.

(ne cherche pas que cela soit marqué comme la réponse, je cherche juste à fournir Un exemple qui était trop long pour s'adapter aux commentaires sur l'excellente réponse de Rob.)

(fixé aux commentaires de Rob ci-dessous.)


5 commentaires

Vous avez tenté de faire trop de changements à la fois. Faire de mon code Utiliser Generic TARRAY aurait été bien, mais vous avez décidé d'ajouter une autre fonctionnalité et de le faire, vous avez enfreint le tout. Je ne pense pas qu'il y ait une entrée qui rend cette fonction fonctionne.


Avez-vous quelque chose de plus spécifique à dire que cela? En fait, j'ai réparé l'erreur que je crois est là (j'avais mon 0/1 transposé sur le si index = 0 puis conditionnel). Je l'utilise actuellement en ce moment et ça marche apparemment bien. S'il y a une erreur, il n'est certainement pas très évident au débogage / runtime. Critique constructive accueillie.


Pouvez-vous expliquer comment cela répond à la question "Utilisation de MOVE () pour insérer / supprimer des éléments d'un tableau dynamique de chaîne"? Je vois une boucle itérative qui n'a rien à voir avec l'utilisation de Whatsover, ne s'adresse pas à un tableau dynamique de la chaîne (A TARRAY générique n'est pas un (code> dynamique de chaîne ), et la question demande spécifiquement de ne pas utiliser de boucle , car l'affiche sait déjà comment le faire. Iow, cela a une pertinence absolument nulle à la question posée ici; Afficher des réponses aléatoires non liées aux questions n'est pas vraiment ce que cela fonctionne.


La transposition n'a pas aidé. Tout temps index est non nul, vous finissez par écrire sur A [-1] . Le premier endroit que vous écrivez doit toujours être un [index] . Regardez mon code. Pourquoi l'index de départ est-il toujours conditionnel? Vous pouvez vous rapprocher de votre fonctionnalité souhaitée en revenant à mon code et en remplaçant chaque occurrence de 1 avec compte .


Merci, c'était plus constructif. En fait, il cherchait principalement mon code après une nuit de sommeil et allait "attendre, pourquoi ai-je écrit ça?" Je n'ai aucune idée à ce stade, mais la réponse était assez évidente. J'ai traversé plusieurs tours de stylo et de quadroughs de papier, alors je suis convaincu que c'est juste à ce stade.



4
votes

Vous n'êtes pas indiquant s'il est important que vous gardes les éléments de la matrice dans le même ordre ou non. Si la commande n'est pas pertinente, vous pouvez alors quelque chose vraiment vraiment rapide comme ceci: xxx

trier la liste
Si vous avez une énorme liste qui doit être modifiée par l'utilisateur, vous pouvez utiliser des méthodes similaires à celle ci-dessus (casser la commande de liste). Lorsque l'utilisateur a fait son édition (après plusieurs suppressions), vous le présentez avec un bouton appelé "liste de tri". Maintenant, il peut faire l'opération longue (tri).
Bien sûr, je suppose ci-dessus que votre liste peut être triée par un certain paramètre.

trier la liste automatiquement
Une alternative consiste à automatiser le processus de tri. Lorsque l'utilisateur a supprimé des choses de la liste, démarrez une minuterie. Continuez à réinitialiser la minuterie si l'utilisateur conserve des éléments. Lorsque la minuterie parvient à déclencher un événement, faites le tri, arrêtez la minuterie.


0 commentaires