Comment épisser un tableau dans Solidity

X0r0N

Comment épisser un tableau dans Solidity


je suis nouveau dans la solidité et j’essaie de trouver la meilleure façon d’épisser un tableau.

en javascript, vous avez: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice

existe-t-il un moyen similaire pour y parvenir dans la solidité?

la seule façon dont je pense qu’il serait possible est de remplacer la valeur de l’index du tableau et de remplacer cette valeur par la valeur de l’élément au prochain index … puis de le faire pour chaque valeur d’index suivante jusqu’à la fin du tableau .

cette méthode semble être coûteuse. Quelqu’un a-t-il des suggestions sur la meilleure façon d’y parvenir?

la principale chose que j’essaie de réaliser est un moyen de garder l’ordre du tableau même si vous pouvez supprimer des éléments du milieu.

suggestion 1

donc y penser, que diriez-vous d’utiliser une liste de structures. par exemple, étant donné une liste de chaînes que nous voulons dans un tableau, que diriez-vous des données à stocker dans une structure avec un champ bool supplémentaire deleted .

 struct   Queue   { 
     string  value ; 
     bool  deleted ; 
 } 

 Queue []   public  listOfItems ; 

 function  deleteItem ( uint  index )   public   { 
     Queue [ index ]. deleted =   true ; 
 } 

étant donné que les opérations de lecture sont gratuites sur ethereum, je peux demander au client de demander des données à un index, si les données de cet index ont été marquées comme deleted , demander automatiquement l’index suivant jusqu’à ce qu’un enregistrement ne soit supprimé.

solution 2

je pourrais utiliser des listes liées pour obtenir une fonctionnalité similaire. de cette façon, si un élément doit être marqué comme deleted , je pourrais mettre à jour la clé de l’élément suivant dans le tableau.

 uint  counter ; mapping ( uint   =>   string )   public  comments ; 

 function  addComment ( string  newComment )   public   { comments [ counter +   1 ]( newComment ); comments [ counter ]. nextItem =  counter +   1 ; 
 } 

 function  removeCommentWithId ( uint  commentId )   public   { comments [ commentId -   1 ]. nextItem =  commentId +   1 ; 
 } 

Réponses


 Rob Hitchens B9lab

Ne le fais pas.

Surtout, évitez les opérations O (n). Reconsidérez la nécessité d’une opération de type épissure. Si vous pensez en avoir besoin, c’est probablement une application sous-optimale de la blockchain.

J’espère que cela aide.

X0r0N

veuillez consulter la suggestion 1 j’ai ajoutée dans le corps de la question.

Rob Hitchens B9lab

Oui. C’est une approche courante. Il gardera les éléments dans l’ordre où ils ont été ajoutés et en marquera certains supprimés. Quelques autres idées ici: ethereum.stackexchange.com/questions/13167/…


 smarx

Vous voudrez peut-être une liste chaînée.

Supprimer un élément puis déplacer tous les autres est la meilleure façon de gérer cela à l’aide d’un tableau. (BTW, je suis presque sûr que c’est comme ça que l’ splice de JavaScript fonctionne aussi.) L’utilisation d’une liste liée vous permettrait de supprimer efficacement un élément.

Cela dit, avez-vous également besoin d’insérer des éléments et de conserver l’ordre de tri? Si oui, comment faites-vous l’insertion? (Cela ressemble également à une opération O (n).) Vous pouvez envisager d’autres structures de données, comme un segment de mémoire ou un arbre équilibré, ou vous pouvez trier à la demande sur le client. Tout dépend de votre scénario.

ÉDITER

En réponse à la modification de la question, c’est bien, mais pensez au rapport attendu des éléments supprimés aux éléments existants. Si, après une longue utilisation, vous avez 10 éléments avec 10 000 éléments supprimés entre eux, vous constaterez que cela est extrêmement inefficace. Une liste chaînée n’a pas ce problème.

Pensez également à utiliser exists = true au lieu de deleted = false . Cela peut économiser du gaz en fonction de l’utilisation prévue.

EDIT 2

Une implémentation à la hâte de listes doublement liées. Veuillez tester avant d’utiliser. 🙂

 pragma solidity ^ 0.4 . 21 ; contract DoublyLinkedList   { 
     struct   Node   { bytes payload ; uint256 next ; uint256 prev ; 
     } uint256 nextNodeID =   1 ;    // 0 is a sentinel value. mapping ( uint256 =>   Node )  nodes ; uint256 head ; uint256 tail ; uint256 count =   0 ; 

     function  append ( bytes payload )   public   { 
         if   ( tail ==   0 )   { 
             // 0 is a sentinel. tail == 0 means head == 0 and the list is empty. head =  nextNodeID ; tail =  nextNodeID ; nodes [ nextNodeID ]. payload =  payload ; 
         }   else   { nodes [ tail ]. next   =  nextNodeID ; nodes [ nextNodeID ]. payload =  payload ; nodes [ nextNodeID ]. prev =  tail ; tail =  nextNodeID ; 
         } nextNodeID +=   1 ; count +=   1 ; 
     } 

     function  validNode ( uint256 nodeID )   internal  view returns ( bool )   { 
         return  nodeID ==  head ||  nodes [ nodeID ]. prev !=   0 ; 
     } 

     function  remove ( uint256 nodeID )   public   { 
         require ( validNode ( nodeID )); 

         Node  storage node =  nodes [ nodeID ]; 

         // Update head and tail. 
         if   ( tail ==  nodeID )   { tail =  nodes [ nodeID ]. prev ; 
         } 
         if   ( head ==  nodeID )   { head =  nodes [ nodeID ]. next ; 
         } 

         // Update previous node's next pointer. 
         if   ( node . prev !=   0 )   { nodes [ node . prev ]. next   =  node . next ; 
         } 

         // Update next node's previous pointer. 
         if   ( node . next   !=   0 )   { nodes [ node . next ]. prev =  node . prev ; 
         } 

         // Reclaim storage for the removed node. 
         delete  nodes [ nodeID ]; count -=   1 ; 
     } 

     function  getNodeIDs ()   public  view returns ( uint256 []  ids )   { ids =   new  uint256 []( count ); uint256 current =  head ; 
         for   ( uint256 i =   0 ;  i <  count ;  i ++)   { ids [ i ]   =  current ; current =  nodes [ current ]. next ; 
         } 
     } 

     function  getPayload ( uint256 nodeID )   public  view returns ( bytes )   { 
         require ( validNode ( nodeID )); 

         return  nodes [ nodeID ]. payload ; 
     } 
 } 

X0r0N

veuillez consulter la suggestion 1 j’ai ajoutée dans le corps de la question.

X0r0N

tu as raison. ce serait très inefficace. en particulier pour le côté client qui pourrait être très lourd sur l’utilisation de la bande passante où chaque demande nécessiterait une nouvelle poignée de main http. mais il semble que la solidité limite assez la façon de gérer un tel cas d’utilisation.

smarx

Avez-vous une objection à l’utilisation d’une liste chaînée?

X0r0N

aucune objection. avez-vous un lien vers où je peux en savoir plus sur les listes liées dans la solidité? je vais l’ajouter avec un exemple aux suggestions ci-dessus.

smarx

J’aurais besoin d’en savoir plus sur votre cas d’utilisation et les opérations que vous allez prendre en charge. Par exemple, vous avez mentionné la suppression du milieu, mais le faites-vous en sautant directement à ce nœud (par exemple, il y a un mappage quelque part qui vous indique où se trouve un nœud) ou en énumérant en commençant au début? Une liste chaînée est triviale à construire, mais je me demande si vous avez besoin d’une liste doublement liée avec un mappage.

 

comment, dans, épisser, Solidity?, Tableau, un

 

yahoo

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *