1

I have such a struct

struct OfferBid {
            string id_user;
            uint qty_energy;
            uint typ;
            uint price_energy;
            uint status;
            uint t_submission;
            uint ts_delivery;
            uint number;
            uint quality_energy;
       }

and I have an array of this struct:

OfferBid[] tempOffers;

I found out how to sort tempOffers by price_energy. I use this function which creates an array of unit from the field price:

function quickSortOffersBidsPrice(Lb.Lib.OfferBid[] memory arr, bool ascending) public view returns(Lb.Lib.OfferBid[] memory) {
        if(arr.length == 0) return arr;
        uint[] memory prices = lib.arr_of_prices_offerbids(arr);
        Lb.Lib.OfferBid[] memory sorted = get_indices_and_sort(prices,arr,ascending);
        return sorted;
    }

which calls these other functions: Here I create an array of unit with the indices of the array of struct.

function get_indices_and_sort(uint[] memory values, Lb.Lib.OfferBid[] memory offers_bids, bool ascending) private pure returns(Lb.Lib.OfferBid[] memory) {
        uint[] memory indices = new uint[](values.length);
        for (uint z = 0; z < indices.length; z++) {
            indices[z] = z;
        }
        Sorting.quickSort_indices(values, 0, int(values.length-1), indices);
        if(!ascending){
            indices = reverseArray(indices);
        }
        Lb.Lib.OfferBid[] memory sorted = new Lb.Lib.OfferBid[](values.length);
        for (uint z = 0; z < indices.length; z++) {
            sorted[z] = offers_bids[indices[z]];
        }
        return sorted;
    }

I sort the array of prices and then at the same time the indices. Then I can sort the original array of struct

function quickSort_indices(uint[] memory arr, int left, int right, uint[] memory indices) public pure {
        int i = left;
        int j = right;
        if (i == j) return;

        uint pivot = arr[uint(left + (right - left) / 2)];

        while (i <= j) {
            while (arr[uint(i)] < pivot) i++;
            while (pivot < arr[uint(j)]) j--;
            if (i <= j) {
                (arr[uint(i)], arr[uint(j)]) = (arr[uint(j)], arr[uint(i)]);
                (indices[uint(i)], indices[uint(j)]) = (indices[uint(j)], indices[uint(i)]);
                i++;
                j--;
            }
        }
        if (left < j)
            quickSort_indices(arr, left, j, indices);
        if (i < right)
            quickSort_indices(arr, i, right, indices);
    }

How can I sort it first by price_energy, and in case of same price_energy, sort it byqty_energy?

3 Answers3

0

Since int256 has a sufficiently large dimension, you can use the composite key for ordering: key= (price_energy<<128) | qty_energy

In addition, it may be more efficient to order the array not after its complete formation, but incrementally - as elements are added.

Mad Jackal
  • 1,219
  • 1
  • 7
  • 9
0

According to this answer. Сustomize a next sample:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Sort {
    uint public total = 5;
    mapping(uint => Item) private itemIdToItem;
    struct Item { 
        uint id;
        uint price;
    }

    constructor() {
        itemIdToItem[1] = Item(1, 2);
        itemIdToItem[2] = Item(2, 5);
        itemIdToItem[3] = Item(3, 1);
        itemIdToItem[4] = Item(4, 3);
        itemIdToItem[5] = Item(5, 4);
    }

    /**
     * @dev Returns tuple(uint256,uint256)[]: 1,2, 2,5, 3,1, 4,3, 5,4 
     */
    function getItems() public view returns(Item[] memory) {
        uint totalMatches = 0;
        Item[] memory matches = new Item[](total);

        for (uint i = 1; i <= total; i++) {
            Item memory e = itemIdToItem[i];
            matches[totalMatches] = e;
            totalMatches++;
        }
        return matches;
    }

    /**
     * @dev Returns tuple(uint256,uint256)[]: 3,1, 1,2, 4,3, 5,4, 2,5
     */
    function sortByPrice() public view returns(Item[] memory) {
        Item[] memory items = getItems();

        for (uint i = 1; i < items.length; i++)
            for (uint j = 0; j < i; j++)
                if (items[i].price < items[j].price) {
                    Item memory x = items[i];
                    items[i] = items[j];
                    items[j] = x;
                }

        return items;
    }
}

haravares
  • 502
  • 1
  • 6
  • 12
0

This function should be enough to sort the array of objects/structs that contain price values. To include the other keys, we can compare them in if condition before swiping the values.

function sortByPrice() public view returns(PrintableResources[] memory) {
    PrintableResources[] memory items = printableResources;

    for (uint i = 1; i < items.length; i++)
        for (uint j = 0; j < i; j++)
            if (items[i].price < items[j].price) {
                PrintableResources memory x = items[i];
                items[i] = items[j];
                items[j] = x;
            }

    return items;
}
GDeep
  • 39
  • 7