Closed. This question is This question is off-topic . It is not currently accepting answers. Want to improve this question? Update the question so it's on-topic for Ethereum Meta Stack Exchange. Closed 3 years ago. Improve this question

Posted in relation to the blog initiative.

Simple and appropriate data organization can challenge Solidity newcomers. It wants us to organize everything in ways many of us aren’t accustomed to. Here are some simple and useful patterns in increasing order of capability.

Simple List using Array

Strengths

In the order of declaration (chronological)

Provides a count (rows)

Random access by Row Number (not ID)

Weaknesses

No random access by Id

No assurance of uniqueness.

No check for duplicates.

Uncontrolled growth of the list

contract simpleList { struct EntityStruct { address entityAddress; uint entityData; // more fields } EntityStruct[] public entityStructs; function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) { EntityStruct memory newEntity; newEntity.entityAddress = entityAddress; newEntity.entityData = entityData; return entityStructs.push(newEntity)-1; } function getEntityCount() public constant returns(uint entityCount) { return entityStructs.length; } }

Mapping with Struct

Strengths

Random Access by unique Id

Assurance of Id uniqueness

Enclose complex arrays, mappings, structs within each “record”

Weaknesses

Unable to enumerate the keys

Unable to count the keys

Needs a manual check to distinguish a default from an explicit record

contract mappingWithStruct { struct EntityStruct { uint entityData; bool isEntity; } mapping (address => EntityStruct) public entityStructs; function isEntity(address entityAddress) public constant returns(bool isIndeed) { return entityStructs[entityAddress].isEntity; } function newEntity(address entityAddress, uint entityData) public returns(bool success) { if(isEntity(entityAddress)) throw; entityStructs[entityAddress].entityData = entityData; entityStructs[entityAddress].isEntity = true; return true; } function deleteEntity(address entityAddress) public returns(bool success) { if(!isEntity(entityAddress)) throw; entityStructs[entityAddress].isEntity = false; return true; } function updateEntity(address entityAddress, uint entityData) public returns(bool success) { if(!isEntity(entityAddress)) throw; entityStructs[entityAddress].entityData = entityData; return true; } }

Array of Structs with Unique Ids

Strengths

Random Access by row number

Assurance of Id uniqueness

Enclose complex arrays, mappings and structs within each “record”

Weaknesses

No random access by Id

Uncontrolled growth of the list

contract arrayWithUniqueIds { struct EntityStruct { address entityAddress; uint entityData; } EntityStruct[] public entityStructs; mapping(address => bool) knownEntity; function isEntity(address entityAddress) public constant returns(bool isIndeed) { return knownEntity[entityAddress]; } function getEntityCount() public constant returns(uint entityCount) { return entityStructs.length; } function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) { if(isEntity(entityAddress)) throw; EntityStruct newEntity; newEntity.entityAddress = entityAddress; newEntity.entityData = entityData; knownEntity[entityAddress] = true; return entityStructs.push(newEntity) - 1; } function updateEntity(uint rowNumber, address entityAddress, uint entityData) public returns(bool success) { if(!isEntity(entityAddress)) throw; if(entityStructs[rowNumber].entityAddress != entityAddress) throw; entityStructs[rowNumber].entityData = entityData; return true; } }

Mapped Structs with Delete-enabled Index

Strengths

Random Access by unique Id or row number

Assurance of Id Uniqueness

Enclose complex arrays, mappings and structs within each “record”

Count the records/Ids

Enumerate the Ids

Ability to logically control the size of the active list

Weaknesses

Marginally increased code complexity

Higher storage cost than alternatives

Key list is inherently unordered

Detailed description: https://medium.com/@robhitchens/solidity-crud-part-1-824ffa69509a#.20k69nqrc

contract mappedWithUnorderedIndexAndDelete { struct EntityStruct { uint entityData; uint listPointer; } mapping(address => EntityStruct) public entityStructs; address[] public entityList; function isEntity(address entityAddress) public constant returns(bool isIndeed) { if(entityList.length == 0) return false; return (entityList[entityStructs[entityAddress].listPointer] == entityAddress); } function getEntityCount() public constant returns(uint entityCount) { return entityList.length; } function newEntity(address entityAddress, uint entityData) public returns(bool success) { if(isEntity(entityAddress)) throw; entityStructs[entityAddress].entityData = entityData; entityStructs[entityAddress].listPointer = entityList.push(entityAddress) - 1; return true; } function updateEntity(address entityAddress, uint entityData) public returns(bool success) { if(!isEntity(entityAddress)) throw; entityStructs[entityAddress].entityData = entityData; return true; } function deleteEntity(address entityAddress) public returns(bool success) { if(!isEntity(entityAddress)) throw; uint rowToDelete = entityStructs[entityAddress].listPointer; address keyToMove = entityList[entityList.length-1]; entityList[rowToDelete] = keyToMove; entityStructs[keyToMove].listPointer = rowToDelete; entityList.length--; return true; } }

There are certainly more ways of combining structs, arrays and mappings. Do you have favorite or interesting pattern? Show us how it works!