2014-08-27 2 views
5

je dois être complètement débile, puisque je ne pouvais pas obtenir tout ce bit: Comment puis-je ajouter des éléments à un tableau sans qu'il soit copié.D: Ajout d'éléments à tableau sans copier

En d'autres termes, disons que je veux créer une grande liste de quelque chose:

int[] arr; 

while (...) { // 1,000,000 iterations 
    ... 
    arr ~= something; 
    ... 
} 

Je ne comprends pas tout à fait quand ~= me contenterai d'ajouter au tableau, et quand il crée une copie de celui-ci . Pour clarifier, je cherche une sémantique comme ArrayList en Java ou C#, c'est-à-dire un conteneur abstrait dans lequel je peux mettre des choses et qui grandira si nécessaire, mais qui reste généralement le même "objet" (ie).

Répondre

9

Cela fonctionne à peu près la même chose qu'un ArrayList fonctionne en ce qu'il a un capacity qui est le nombre d'éléments qu'il peut développer jusqu'à ce qu'il doive se réallouer. Cependant, il est compliqué par le fait que le passage d'un tableau à une fonction le découpe plutôt que d'avoir le même tableau. Si vous n'utilisez qu'une variable locale et que vous ne l'attribuez à rien, cela ne devrait pas avoir d'importance dans les réaffectations, sauf pour l'efficacité.

L'article que vous devriez lire est ceci: http://dlang.org/d-array-article.html

Je pense qu'il utilise une terminologie un peu mal, car il fait référence au bloc de mémoire que le temps d'exécution gère comme étant le tableau dynamique plutôt que T[] - qui est ce que la spécification considère comme un tableau dynamique, alors que le bloc de mémoire vient juste d'être ce qui soutient le tableau pour le moment - mais il explique parfaitement de nombreux détails sur le fonctionnement des tableaux dans D. Donc, ça devrait être très instructif.

En outre, vous devriez probablement envisager d'utiliser std.array.Appender si vous faites beaucoup de appending. par exemple.

auto app = appender!(int[])(); 

while (...) { // 1,000,000 iterations 
    ... 
    app.put(something); 
    ... 
} 

int[] arr = app.data; 

Cela rendra l'ajout plus efficace. Cependant, en général, vous ferez probablement mieux si vous créez des tableaux et que vous les exécutez plutôt que de les ajouter à nouveau plus tard. Évidemment, cela ne convient pas à tous les cas d'utilisation, mais si vous le faites, vous n'aurez jamais à vous soucier de savoir si une tranche fait toujours référence à la même mémoire qu'une autre - soit cela ou code de manière à ne pas compter sur deux tranches se référant à la même mémoire.

Une alternative serait d'utiliser std.container.Array qui est un type de référence complet (au lieu d'un type demi-référence comme matrices dynamiques de D sont). Bien sûr, si vous voulez faire circuler un tableau, que plusieurs parties de celui-ci se réfèrent à la même mémoire, et que vous y ajoutiez, vous devriez probablement utiliser Array à la place.

+0

Donc, pour résumer pour voir si je comprends: Tant que le tableau est une variable locale qui n'est pas passé autour, ou un membre de la classe, ou passé autour comme 'ref', je peux le traiter comme un' ArrayList '. Pour l'ajout en bloc, utilisez 'appender'. Pour passer un grand tableau légèrement modifié, utilisez 'Array'. Est-ce plus ou moins correct? –

+0

@AmirAbiri Plus ou moins, oui. Passer un tableau donne des tableaux qui pointent vers la même mémoire mais qui ne sont pas des références les uns aux autres, donc si l'un d'entre eux doit réallouer, il ne se référera plus à la même mémoire que les autres. Donc, si vous ne l'ajoutez pas après l'avoir fait circuler, il est bon de le passer, mais si vous le faites, vous devez soit le passer par 'ref', soit utiliser une autre solution (comme' Array'). Et «Appender» rend l'ajout plus efficace, donc si vous construisez un tableau en ajoutant beaucoup d'ajouts (plutôt que d'ajouter juste quelques fois), il est préférable de l'utiliser. –