How to sort data in a String

Board: Nano 33 BLE Sense Rev2
I want to sort data as it is in the string 'b', but after sorting, the data is sorted in ascending order. What can I do to correct it? Also if I want to read only the last string of a very large file, is it better to just store one string in a file and after reading it, delete and recreate the file to write new data OR store data in same file and read the last string? I want to make the code run faster.

image

image

Code:

#include <SD.h>

const int chipSelect = 2;        // SD card chip select pin
const int stringLength = 17;     // maximum length of the string
char inputString[stringLength];  // a string to hold incoming data from SD card
bool stringComplete = false;     // whether the string is complete or not
String a = "1,2,3,4,5,6,7,8,9,0,123,3,5,6,7,8,9,0,12,4,67,89";
char b[] = "3,2,101300,28800";  //17 max, min 12  , Packet,ref,count,state
File dataFile;

void setup() {
  Serial.begin(9600);  // initialize serial communication
  while (!Serial) {
    ;  // wait for serial port to connect
  }

  if (!SD.begin(chipSelect)) {  // initialize SD card
    Serial.println("Card failed, or not present");
    while (1)
      ;
  }

  SD.remove("data.txt");
  dataFile = SD.open("data.txt", FILE_WRITE);
  dataFile.println(b);
  dataFile.close();

  Serial.println(strlen(b));
  // open the file for reading:
  dataFile = SD.open("data.txt", FILE_READ);
  if (dataFile) {
    while (dataFile.available()) {
      char c = dataFile.read();
      if (c == '\n') {                                   // the end of a string
        inputString[dataFile.position() - 1] = '\0';     // add null terminator to the string
        stringComplete = true;                           // the string is complete
      } else if (dataFile.position() >= stringLength) {  // the string is too long
        inputString[dataFile.position() - 1] = '\0';     // add null terminator to the string
        stringComplete = true;                           // the string is complete
        dataFile.seek(dataFile.position() + 1);          // skip the rest of the line
      } else {
        inputString[dataFile.position() - 1] = c;  // add a character to the string
      }
    }
    dataFile.close();
  } else {
    Serial.println("Unable to open file");
  }

  if (stringComplete) {
    // sort the data
    int dataArray[4];
    int i = 0;
    char* ptr = strtok(inputString, ",");
    while (ptr != NULL && i < 4) {
      dataArray[i] = atoi(ptr);  // convert string to integer
      ptr = strtok(NULL, ",");
      i++;
    }
    for (int j = 0; j < i - 1; j++) {
      for (int k = j + 1; k < i; k++) {
        if (dataArray[j] > dataArray[k]) {
          int temp = dataArray[j];
          dataArray[j] = dataArray[k];
          dataArray[k] = temp;
        }
      }
    }
    // print the sorted data
    Serial.print("Sorted data: ");
    for (int j = 0; j < i; j++) {
      Serial.print(dataArray[j]);
      if (j < i - 1) {
        Serial.print(", ");
      }
    }
    Serial.println();
  } else {
    Serial.println("No complete string found");
  }
}

void loop() {
  // do nothing
}

Isn't that what sorting means? To put things in order?

Or are you saying you code doesn't work? If so, what results is it producing?

And I might as well guess, given what you've said so far, but it sounds like storing only the one thing you are interested in is better. If you keep storing everything and using only the last line, how's that going to work forever?

a7

The code does work, but the sorted data is in ascending order. I am making a recovery system so that in case of power loss, the last state of the system can be retrieved. I want to store the sorted data in specific variable and the string data in the actual implementation is variable. At some point in time the first value in the string might be lesser then the second ones, and this will change the data in sorted string.

Explain how that is different from what you want.

I (and I suspect everybody else reading this post) have no idea what you are trying to do.

Try and explain simply, and clearly, what it is you are trying to achieve.

This does not make sense...

The string b [ ] is variable and the data in it is logged data of system state and some sensor data and they are variable , which I need to retrieve from SD card in case there is a power loss and the board restarts .

The string I want to read and sort is char b[ ] = "3,2,101300,28800";
When I sort it, I expect that the sorted data in the dataArray[ ] is in the same order. i.e. dataArray[0]=3, dataArray[1]=2,dataArray[2]=101300,dataArray[4]=28800. But as you can see below in this photo

image

of the sorted data in serial monitor, the data is not in same order as in the original b [] string. Instead, the data is sorted in ascending order. For eg. If I change the string b to "8,5,101300,28800" , the output is "5,8,101300,28800".

I want to extract data from the b [] string and assign the values stored in dataArray to four variables: x,y,z,w. Since the sorted data is not in the form of the data parsed in the original string, there will be a case where value to be stored in x is stored in y because of the ascending data sorting and vice versa.

That's what "sorting" is. If it's not what you want, why are you sorting it?

Is there any other method then using strtok() function which I can use for this purpose?

If you just want to parse based on ","
https://cplusplus.com/reference/cstring/strchr/

In Adafruit's GPS lib, she does this:


  if (strstr(nmea, "$GPRMC")) {
   // found RMC
    char *p = nmea;

    // get time
    p = strchr(p, ',')+1;
    float timef = atof(p);
    uint32_t time = timef;
    hour = time / 10000;
    minute = (time % 10000) / 100;
    seconds = (time % 100);

    milliseconds = fmod(timef, 1.0) * 1000;
    p = strchr(p, ',')+1;  // A/V?
    p = strchr(p, ',')+1;  // lat
    p = strchr(p, ',')+1;  // N/S?
    p = strchr(p, ',')+1;  // lon
    p = strchr(p, ',')+1;  // E/W?
    p = strchr(p, ',')+1;  // speed
    p = strchr(p, ',')+1;  // angle

    p = strchr(p, ',')+1;
    uint32_t fulldate = atof(p);
    day = fulldate / 10000;
    month = (fulldate % 10000) / 100;
    year = (fulldate % 100);
    // some older GPS modules only send GGA messages until full-GPS sync
    // so, only want to use the GGA sentences until RMC is available as
    // GGA only has time info and not date
    ColdGPS = false ;
    return true;
  }
  else if (ColdGPS && strstr(nmea, "$GPGGA")) {
    // found GGA
    char *p = nmea;
    // get time
    p = strchr(p, ',')+1;
    float timef = atof(p);
    uint32_t time = timef;
    hour = time / 10000;
    minute = (time % 10000) / 100;
    seconds = (time % 100);
    milliseconds = fmod(timef, 1.0) * 1000;
    return true;
  }
    return false;
}

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.