How to filter a multidimensional array in Rust?

62 Views Asked by At

I have the JSON data below and I need to parse it using Rust. Using serde, I can access some of the JSON as such:

let v: serde_json::Value = serde_json::from_str(&data).expect("Unable to parse");
let sessions = v["data"]["sessions"].as_array().unwrap();
let programs = v["data"]["programs"].as_array().unwrap();

But how do I filter for a single programData array item using the programs.id value? I'm trying something like this but I can't get it right:

    for x in programs {
            let programId = &x["id"];

            // not working - produces 'no implementation' error while building
            let programSessions = sessions.iter().filter(|&f| f["programData"].as_array().unwrap()["programRefId"] == programId).collect();
        }
{
  "data": {
    "name": "my name",
    "sessions": [
      {
        "id": 1,
        "programData": [
          {
            "dataPhase": 1,
            "programRefId": 2,
            "programSpecificData": {
              "completed": false
            }
          },
          {
            "dataPhase": 2,
            "programRefId": 3,
            "programSpecificData": {
              "completed": true
            }
          }
        ]
      }
    ],
    "programs": [
      {
        "id": 3
      }
    ]
  }
}
1

There are 1 best solutions below

1
suchislife On BEST ANSWER

If you wanna filter for a single programData array item using program.id you need to change a couple things. Looks like you're directly comparing a serde_json::Value with anothoer serde_json::Value within a nested structure which can lead to issues. You're also trying to filer on programData as if it's a single object when it's actually an array.

You should loop through each program, then for each program loop through each session then in each session filter programData itemas based on programRefId.

use serde_json::Value;

fn main() {
    let data = r#"
    {
        "data": {
            "name": "my name",
            "sessions": [
                {
                    "id": 1,
                    "programData": [
                        {
                            "dataPhase": 1,
                            "programRefId": 2,
                            "programSpecificData": {
                                "completed": false
                            }
                        },
                        {
                            "dataPhase": 2,
                            "programRefId": 3,
                            "programSpecificData": {
                                "completed": true
                            }
                        }
                    ]
                }
            ],
            "programs": [
                {
                    "id": 3
                }
            ]
        }
    }
    "#;

    let v: Value = serde_json::from_str(data).expect("Unable to parse");
    let sessions = v["data"]["sessions"].as_array().unwrap();
    let programs = v["data"]["programs"].as_array().unwrap();

    for program in programs {
        let program_id = program["id"].as_i64().unwrap(); // Assuming id is always an integer.

        for session in sessions {
            let program_data = session["programData"].as_array().unwrap();

            let program_sessions: Vec<&Value> = program_data.iter().filter(|&f| {
                // Assuming programRefId is always present and an integer.
                f["programRefId"].as_i64() == Some(program_id)
            }).collect();

            // Now you have the filtered programSessions for the current program_id
            // Do something with program_sessions...
            println!("Filtered program sessions for program id {}: {:?}", program_id, program_sessions);
        }
    }
}

Rust Playground Link

Filtered program sessions for program id 3: [Object {"dataPhase": Number(2), "programRefId": Number(3), "programSpecificData": Object {"completed": Bool(true)}}]