1

I have created a function that receive some values from users an store them in a mapping. How to arrange the stored values in mapping according to a certain value ( Priority as in the shown example below)?

 pragma solidity ^0.4.24; 

  contract Test {

// storage is packed based on how much data we actually want to store,
// to minimise the storage costs, we're going to use expected uint types
struct StudentType {
    uint8 bonus;        // 0 - 255
    uint16 value1;      // 0 - 65535
    uint16 value2;      // 0 - 65535
    uint16 Priority;    // 0 - 65535
}

mapping (address => StudentType) public studentsByAddress; 
mapping (uint256 => address) public studentsByInsertId; 
uint256 public studentCount = 0;

function saveNewRecord(address _address, uint8 _bonus, uint16 _value1, uint16 _value2) public {          

    // instance of struct student and map it to students mapping;
    StudentType storage student = studentsByAddress[_address]; 
    student.bonus = _bonus;
    student.value1 = _value1;
    student.value2 = _value2;

    student.Priority = this.calculatePriority( _value1, _value2, _bonus);

    // map address to current insert id
    // ++uint makes our index start at 1 since the incrementation happens before 
    // if you want it to start at 0, then do uint++
    studentsByInsertId[studentCount++] = _address;

}

/*

    depending on the precision you actually want the more "zeroes" you're going to use. 
*/

function calculatePriority(uint16 _value1, uint16 _value2, uint8 _bonus) pure public returns ( uint16 ) {
    // store the calculation in a big enough value
    uint256 result = ( ( ( 50 * _value1 ) + ( 50 * _value2 ) ) / _bonus ) / 100;

    // convert result
    return uint16( result );
}

/*
    not really needed since you can use the "studentsByAddress" mapping method created by solidity
    unless you want to "hide" or manipulate some data
*/
function get_ESU(address ins) view public returns (uint, uint, uint) {
    return (
        studentsByAddress[ins].value1,
        studentsByAddress[ins].value2,
        studentsByAddress[ins].Priority
    );
}

 }

2 Answers 2

1

If your smart contract doesn't depend on the sorting, I would suggest to do the sorting off-chain. Every time you insert a new student, you can emit an event. Off-chain, in your application, you can fetch all the events and sort the list by priority. If you need the sorting on-chain in your smart contract code, you'll have to implement a sorting algorithm in your contract.

EDIT See Sorting an Array of integer with Ethereum for inspiration.

3
  • actually, it depends on the sorting. Any idea of how to implement such a sorting algorithm for my case
    – Mohamed
    Oct 4, 2018 at 21:25
  • It depends on which sorting algorithm you wish to use. You could use arrays and then write for example merge sort on this array to sort the elements by priority. See ethereum.stackexchange.com/questions/1517/… for inspiration.
    – ivicaa
    Oct 4, 2018 at 21:41
  • @ I read the link but I am not able to apply the quick sort to my case. Assume we have an array that stores all the incoming addresses. How can I sort these addresses based on its each student priority value
    – Mohamed
    Oct 5, 2018 at 1:57
0

Good question.

First to avoid you headhach, and avoiding by surprise on gas fee. Please read this answer: https://ethereum.stackexchange.com/a/55563/111776

You must keep in mind, loop are expensive even for memory variables, because the gas fee is not linear but quadratic. (A good limit to fix is around 1000 for a complexity O(1))

2ndly: mapping constraint You need to know before sorting all your keys elements of your mapping to iterate on it. So as you proposed in the discussion, for the same architecture, you must have an array saving the address. (Let's call it arr1)

3rd: Sorting Did you check that: https://medium.com/coinmonks/sorting-in-solidity-without-comparison-4eb47e04ff0d? After you decide the best algo, you need to keep order information, for that, better to arrange your array arr1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.