0

Is there a way to sort json by value in it

e.g. [{"chapter": "3"},{"chapter": "1.5"},{"chapter": "2"},{"chapter": "1"}]

Result should be [{"chapter": "1"},{"chapter": "1.5"},{"chapter": "2"},{"chapter": "3"}]

match serde_json::from_str(&manga_json) {
    Ok(json_value) => match json_value {
        Value::Object(obj) => {
            if let Some(data_array) = obj.get("data").and_then(Value::as_array) {
                // data_array is in format [{"chapter":"3"},{"chapter":"2"}]
            }
        }
        _ => {
            println!("JSON is not an object.");
        }
    },
    Err(err) => println!("Error parsing JSON: {}", err),
}

EDIT

I forgot that chapter is in attributes

// data format is [{"attributes":{"chapter":"3"}},{"attributes":{"chapter":"2"}}]

I made this function but this its wrong

fn sort(data: &Vec<Value>) -> Vec<Value> {
    let mut data_array = data.to_owned();
    data_array.sort_unstable_by_key(|v| {
        v.get("attributes")
            .unwrap()
            .get("chapter")
            .and_then(Value::as_i64)
    });
    return data_array;
}

This is what I get when i print it

Object {"attributes": Object {"chapter": String("35")}}

But it still don't sort what am I missing

EDIT 2

fn sort(data: &Vec<Value>) -> Vec<Value> {
    let mut data_array = data.to_owned();
    data_array.sort_unstable_by_key(|v| {
        v.get("attributes")
            .unwrap()
            .get("chapter")
            .unwrap()
            .as_f64();
    });
    return data_array;

This still doesn't sort.

EDIT 3

fn sort(data: &Vec<Value>) -> Vec<Value> {
    let mut data_array = data.to_owned();
    data_array.sort_unstable_by_key(|v| {
        return v
            .get("attributes")
            .unwrap()
            .get("chapter")
            .unwrap()
            .as_str()
            .unwrap()
            .split(".")
            .next()
            .unwrap()
            .parse::<i32>()
            .unwrap();
    });
    return data_array;
}

I came to conclusion that this is working and I'll leave it at that, I wanted to sort it by float number but since sort_unstable_by_key is NOT able to process float, I would just cut the decimal part and leave it at that, if there is a way to sort it by float number, thanks in advance

FINAL EDIT


fn sort(data: &Vec<Value>) -> Vec<Value> {
    let mut data_array = data.to_owned();
    data_array.sort_unstable_by(|v, b| {
        return v
            .get("attributes")
            .unwrap()
            .get("chapter")
            .unwrap()
            .as_str()
            .unwrap()
            .parse::<f32>()
            .unwrap()
            .total_cmp(
                &b.get("attributes")
                    .unwrap()
                    .get("chapter")
                    .unwrap()
                    .as_str()
                    .unwrap()
                    .parse::<f32>()
                    .unwrap(),
            );
    });
    return data_array;
}

This the final function

Hovercraft
  • 17
  • 5
  • [`sort_by_key (|v| v.get ("chapter"))`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.sort_by_key) – Jmb Aug 31 '23 at 09:44
  • 1
    @Jmb [`sort_unstable_by_key(|v| v.get("chapter"))`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.sort_unstable_by_key) – Chayim Friedman Aug 31 '23 at 09:59
  • But it is better to use a fixed struct. – Chayim Friedman Aug 31 '23 at 09:59
  • Nit: [you want to take `&[T]`, not `&Vec`](https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-string-vec-or-box-as-a-function). – Chayim Friedman Aug 31 '23 at 10:39
  • 1
    If the data is really as you've shown, then `chapter` is not a number but a string, and `Value::as_i64` will return `None`. All `None`s compare equal, so this does nothing, except for randomizing the array (for unstable sorting). – Chayim Friedman Aug 31 '23 at 10:40
  • 1
    Your Edit 2 is still returning `None`. What you want is more like `.as_str().unwrap().parse::().unwrap()`. – Chayim Friedman Aug 31 '23 at 10:52
  • Probably want `parse::` instead since some of the chapter numbers seem to be decimals like `1.5` based on the example data – mousetail Aug 31 '23 at 11:03
  • `sort_unstable_by_key` is not able to process float only `` and `` – Hovercraft Aug 31 '23 at 11:18
  • 2
    You can use [`total_cmp`](https://doc.rust-lang.org/std/primitive.f32.html#method.total_cmp) to compare floats – mousetail Aug 31 '23 at 11:25
  • 2
    @Hovercraft Can there be chapter numbers of the form `"1.2.3"` as well? If so, you can't use floating point numbers, and either way it feels a bit iffy to me. – Sven Marnach Aug 31 '23 at 12:34
  • @SvenMarnach Then the proper solution is probably to split on `.`, parse each item as an `usize` and collect: `sort_unstable_by_key (|v| v.get ("attributes").unwrap().get ("chapter").unwrap().as_str().split ('.').map (|i| i.parse::().unwrap()).collect::>())` – Jmb Aug 31 '23 at 13:08

0 Answers0