¿Devolver una matriz de asignaciones que reflejen el estado global entre asociaciones de estructuras?

Estoy buscando una construcción que sea algo así como "devolver una lista de pares de valores clave", que creo que se implementaría como una matriz de asignaciones. ¿Está bien?

Es decir, me gustaría una estructura de datos que contenga una lista de (clave, valor) que usaré como un estado global que vincula algunas estructuras para asociarlas con otras.

Lo que quiero decir es algo como:

// so I have place structs
struct Place {
  uint8 placeid;
  string nameOfPlace;
  ...etc
}

// and a place can contain no more than 1 banner.    
// banners have all been to a place, but they aren't necessarily
// in a place right now. They may have been replaced with another 
// banner.
struct Banner {
  uint8 bannerid;
  uint8 placeAt; // this must match a placeid
  string thingTheBannerSays;
  uint8 timestamp;
}

Place[] places;                        // list all places
mapping(uint8 => Place)  placesById    // given an id, return the place
Banner[] banners;
mapping(uint8 => Banner)  bannersById  // given an id, return the place

// what's missing for me is a data structure
// with global state of [(place0,bannerN),(place1,bannerM)] 
// for all places.  This is what I'm looking for.

function listBannersAtPlacesRightNow() returns (???? arrayOfMappings) {
  ??? mappings[] = arrayOfMappings
  for(uint8 i =0; i < places.length; i++) {
     maxTime[i] = 0;       // declare this correctly
     idWhereMaxTime[i] = 0; // gross, would rather be null
     for(uint8 j=0; j < banners.length; j++) {
        if(banners[j].timestamp > maxTime[i]) {
          maxTime[i] = banners[j].timestamp // high water ;
          idWhereMaxTime[i] = banners[j];
        }
       }
     arrayOfMappings[i] = (places[i], idWheremaxTime[i]);
   }
 return arrayOfMappings;
 }

Lo siento, soy nuevo en esto, pero si no está claro, en palabras, me gustaría alguna variable para mantener el estado global que dice "Soy un lugar, puedo tener 0 o 1 banners. Aquí hay una lista de todos los lugares y sus pancartas actuales. Las pancartas se pueden vincular exactamente a un lugar y nunca reutilizarse".

Cuasi-pitón feo que podría aclarar la cuasi solidez fea, esto sería algo así como:

places = [{"placeid": 0, "nameofplace": "home"}, {"placeid":1, "nameofplace": "center"}]

banners = [
{"bannerid": 0, "placeAt": 0, "thingthebannersays": "hello!"},
{"bannerid": 1, "placeAt": 0, "thingthebannersays": "hello again from home!"},
{"bannerid": 2, "placeAt": 0, "thingthebannersays": "this replaces 1!"},
{"bannerid": 3, "placeAt": 1, "thingthebannersays": "this is at center!"}]

bannerAtPlaces = [(0,2), #place 0 has current banner 2
                  (1,3)  #place 1 has banner 3
]

def setBannerAtPlaces(placeid, bannerid):
  # this updates bannerAtPlaces according to some rules
  # such as the most-recent timestamp given in the solidity
  # section

# BUT If I wanted to see which places contained which banners, I'd just
# print(bannerAtPlaces).  This is the call I'm looking to repeat
# in solidity.

Todo esto surge porque prefiero que la estructura de Place contenga un campo para bannerid, pero desafortunadamente, quiero que Place pueda tener 0 banners, y parece que no puedo inicializar un valor nulo para eso --- Yo debe estar por defecto en bannerid = 0. Pero bannerid==0es un bannerid real. No puede estar en dos lugares a la vez, ya está en otro lugar y no puede ser el banner predeterminado en todos los lugares nuevos.

El motivo de una lista que especifique los estados globales sería representar esto fácilmente en el navegador, como una galería que muestra todos los pares (Lugar, Banner).

Ahora estoy viendo una pregunta similar aquí .

Respuestas (1)

No estaba muy seguro acerca de la cardinalidad de su descripción. Fui con "un banner solo puede estar en un lugar a la vez y un lugar tiene o no tiene exactamente 1 banner".

Los forbucles son un problema serio en Solidity. Necesitamos organizar estructuras de datos para que podamos completar todo a un costo de gas constante en cualquier escala: O (1). Vea esto: https://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad

No creo que necesite uniones de uno a muchos, pero en caso de que eche un vistazo a esto para obtener ideas: https://medium.com/@robhitchens/enforcing-referential-integrity-in-ethereum-smart- contratos-a9ab1427ff42

Ese vínculo te arroja al fondo. Se vincula a la serie CRUD que explica los patrones que usé para realizar este boceto rápido:

pragma solidity 0.4.25;

contract Banners {

    struct BannerStruct {
        string marque;
        bytes32 placeId; // 0 or 1 placeId
        uint idPointer;
    }

    struct PlaceStruct {
        string name;
        bytes32 bannerId; // 0 or 1 bannerId
        uint idPointer;
    }

    mapping(bytes32 => BannerStruct) public bannerStructs;
    mapping(bytes32 => PlaceStruct) public placeStructs;

    bytes32[] public bannerIdList;
    bytes32[] public placeIdList;

    function getBannerCount() public view returns(uint) {
        return bannerIdList.length;
    }

    function getPlaceCount() public view returns(uint) {
        return placeIdList.length;
    }

    function isBanner(bytes32 bannerId) public view returns(bool) {
        if(bannerIdList.length==0) return false; // there aren't any, so false
        return bannerIdList[bannerStructs[bannerId].idPointer] == bannerId;
    }

    function isPlace(bytes32 placeId) public view returns(bool) {
        if(placeIdList.length==0) return false;
        return placeIdList[placeStructs[placeId].idPointer] == placeId;
    }

    function placeHasBanner(bytes32 placeId) public view returns(bool) {
        return isBanner(placeStructs[placeId].bannerId);
    }

    function newBanner(bytes32 bannerId, string marque) public returns(bool) {
        require(!isBanner(bannerId)); // no dups
        bannerStructs[bannerId].marque = marque;
        bannerStructs[bannerId].idPointer = bannerIdList.push(bannerId) - 1;
        return true;
    }

    function newPlace(bytes32 placeId, string name) public returns(bool) {
        require(!isPlace(placeId));
        placeStructs[placeId].name = name;
        placeStructs[placeId].idPointer = placeIdList.push(placeId) - 1;
        return true;
    }

    function setPlaceBanner(bytes32 placeId, bytes32 bannerId) public returns(bool) {
        require(isPlace(placeId));
        require(isBanner(bannerId));
        if(bannerStructs[bannerId].placeId != 0) { // moving it. A banner can only be in one place???
            bytes32 oldPlace = bannerStructs[bannerId].placeId;
            placeStructs[oldPlace].bannerId = bytes32(0);
        }
        bannerStructs[bannerId].placeId = placeId;
        placeStructs[placeId].bannerId = bannerId;
    }
}

A medida que avanza, también encontrará que probablemente desee reducir la cantidad de metadatos almacenados en la cadena. Dejé mis estructuras escasas por este motivo. https://blog.b9lab.com/the-joy-of-minimalism-in-smart-contract-design-2303010c8b09

Espero eso ayude.

Esta es una respuesta muy completa y bastante útil cuando empiezo. Gracias.
Tus enlaces también son muy útiles. Con respecto a la cardinalidad, estaba apuntando a "un banner solo DEBE estar en un lugar a la vez y un lugar tiene o no tiene exactamente 1 banner". Entonces, la idea de que una pancarta siempre tiene 1 lugar, pero un lugar tiene 0 o 1 pancartas (digamos que solo hay 1 asta de bandera, pero una pancarta grande se encuentra al lado). Sin embargo, puedo trabajar con tus consejos y enlaces allí. ¡Gracias!
Me preguntaba sobre eso. El ejemplo está bastante cerca, pero no aplica la regla de que cada banner debe tener un lugar. Ciertamente factible con algunos ajustes más.