如何通过 属性 将 JSON 对象的数组整理成包含每个对象属性的向量的结构?
How to collate an array of JSON objects by a property into a struct containing vectors of each object's properties?
我正在接收传感器数据流,我需要汇总这些数据并对其执行基本统计(平均值、最大值、最小值等)。有多个值,但传感器数据可能不一致,并且某些值可能会丢失。
从书上看,当缺少 luminosity
或 color
的值时,似乎应该使用 Option
,但我对此感到困惑。
这是我的传感器数据的示例:
[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]
每个传感器的数据将存储在以下结构的实例中:
struct Data {
pub luminosity: Vec<String>,
pub color: Vec<String>,
}
我想遍历上面的 JSON 对象,将传感器匹配到正确的结构实例("right" 传感器到 "right" 传感器结构)并推送每个对象的内容JSON 对向量的观察(在每个结构实例中)。
需要记录缺失值,以便对于每个 "observation" 对应传感器结构实例的结构中的每个向量都有一个推送操作。
像这样的东西应该有用。它使用 Serde 将每个 JSON 数组元素读入具有所需传感器名称 String
的辅助结构,以及传感器每个值的 Option<String>
数据。然后它遍历这些读数并将它们插入到地图中,其中键是传感器名称,值是每个传感器值的数据向量。
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::collections::BTreeMap as Map;
use std::error::Error;
#[derive(Debug, Default)]
struct Data {
luminosity: Vec<Option<String>>,
color: Vec<Option<String>>,
}
fn main() {
let input = r##"[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]"##;
let m = read_sensor_data(input).unwrap();
println!("{:#?}", m);
}
fn read_sensor_data(input: &str) -> Result<Map<String, Data>, Box<Error>> {
// Private helper struct that matches the format of the raw JSON
#[derive(Deserialize)]
struct RawReading {
sensor: String,
luminosity: Option<String>,
color: Option<String>,
}
// Deserialize the raw data
let raw_readings: Vec<RawReading> = serde_json::from_str(input)?;
// Loop over raw data and insert each reading into the right sensor's struct
let mut m = Map::new();
for raw in raw_readings {
// Look up this sensor's Data struct
let sensor = m.entry(raw.sensor).or_insert_with(Data::default);
// One push for every vector in the struct, even for missing observations
sensor.luminosity.push(raw.luminosity);
sensor.color.push(raw.color);
}
Ok(m)
}
您可以 稍微 更有效率,但需要更多代码。如果您创建自己的 Visitor
实现,则不需要反序列化 Vec
:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use std::collections::HashMap;
use std::fmt;
use serde::de::{Deserialize, Deserializer, Visitor};
#[derive(Debug, Default)]
struct Data {
luminosity: Vec<Option<String>>,
color: Vec<Option<String>>,
}
struct Wrapper(HashMap<String, Data>);
impl<'de> Deserialize<'de> for Wrapper {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(WrapperVisitor)
}
}
struct WrapperVisitor;
impl<'de> Visitor<'de> for WrapperVisitor {
type Value = Wrapper;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of measurement objects")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
#[derive(Debug, Deserialize)]
struct DataPoint {
sensor: String,
luminosity: Option<String>,
color: Option<String>,
}
let mut all_data = HashMap::new();
while let Some(data_point) = seq.next_element::<DataPoint>()? {
let data = all_data
.entry(data_point.sensor)
.or_insert_with(Data::default);
data.luminosity.push(data_point.luminosity);
data.color.push(data_point.color);
}
Ok(Wrapper(all_data))
}
}
fn main() {
let input = r###"
[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]
"###;
let data = serde_json::from_str::<Wrapper>(input).expect("Nope");
let data = data.0;
println!("{:#?}", data);
}
这会产生输出:
{
"left": Data {
luminosity: [
Some("50"),
None,
Some("30")
],
color: [
Some("(255,0,0)"),
Some("#0f0"),
None
]
},
"right": Data {
luminosity: [
Some("20"),
Some("40"),
None
],
color: [
None,
Some("(255,0,0)"),
Some("(0,0,0)")
]
},
"top": Data {
luminosity: [
Some("10")
],
color: [
None
]
}
}
我正在接收传感器数据流,我需要汇总这些数据并对其执行基本统计(平均值、最大值、最小值等)。有多个值,但传感器数据可能不一致,并且某些值可能会丢失。
从书上看,当缺少 luminosity
或 color
的值时,似乎应该使用 Option
,但我对此感到困惑。
这是我的传感器数据的示例:
[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]
每个传感器的数据将存储在以下结构的实例中:
struct Data {
pub luminosity: Vec<String>,
pub color: Vec<String>,
}
我想遍历上面的 JSON 对象,将传感器匹配到正确的结构实例("right" 传感器到 "right" 传感器结构)并推送每个对象的内容JSON 对向量的观察(在每个结构实例中)。
需要记录缺失值,以便对于每个 "observation" 对应传感器结构实例的结构中的每个向量都有一个推送操作。
像这样的东西应该有用。它使用 Serde 将每个 JSON 数组元素读入具有所需传感器名称 String
的辅助结构,以及传感器每个值的 Option<String>
数据。然后它遍历这些读数并将它们插入到地图中,其中键是传感器名称,值是每个传感器值的数据向量。
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::collections::BTreeMap as Map;
use std::error::Error;
#[derive(Debug, Default)]
struct Data {
luminosity: Vec<Option<String>>,
color: Vec<Option<String>>,
}
fn main() {
let input = r##"[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]"##;
let m = read_sensor_data(input).unwrap();
println!("{:#?}", m);
}
fn read_sensor_data(input: &str) -> Result<Map<String, Data>, Box<Error>> {
// Private helper struct that matches the format of the raw JSON
#[derive(Deserialize)]
struct RawReading {
sensor: String,
luminosity: Option<String>,
color: Option<String>,
}
// Deserialize the raw data
let raw_readings: Vec<RawReading> = serde_json::from_str(input)?;
// Loop over raw data and insert each reading into the right sensor's struct
let mut m = Map::new();
for raw in raw_readings {
// Look up this sensor's Data struct
let sensor = m.entry(raw.sensor).or_insert_with(Data::default);
// One push for every vector in the struct, even for missing observations
sensor.luminosity.push(raw.luminosity);
sensor.color.push(raw.color);
}
Ok(m)
}
您可以 稍微 更有效率,但需要更多代码。如果您创建自己的 Visitor
实现,则不需要反序列化 Vec
:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use std::collections::HashMap;
use std::fmt;
use serde::de::{Deserialize, Deserializer, Visitor};
#[derive(Debug, Default)]
struct Data {
luminosity: Vec<Option<String>>,
color: Vec<Option<String>>,
}
struct Wrapper(HashMap<String, Data>);
impl<'de> Deserialize<'de> for Wrapper {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(WrapperVisitor)
}
}
struct WrapperVisitor;
impl<'de> Visitor<'de> for WrapperVisitor {
type Value = Wrapper;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence of measurement objects")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
#[derive(Debug, Deserialize)]
struct DataPoint {
sensor: String,
luminosity: Option<String>,
color: Option<String>,
}
let mut all_data = HashMap::new();
while let Some(data_point) = seq.next_element::<DataPoint>()? {
let data = all_data
.entry(data_point.sensor)
.or_insert_with(Data::default);
data.luminosity.push(data_point.luminosity);
data.color.push(data_point.color);
}
Ok(Wrapper(all_data))
}
}
fn main() {
let input = r###"
[
{
"sensor": "left",
"luminosity": "50",
"color": "(255,0,0)"
},
{
"sensor": "left",
"color": "#0f0"
},
{
"sensor": "right",
"luminosity": "20"
},
{
"sensor": "right",
"luminosity": "40",
"color": "(255,0,0)"
},
{
"sensor": "left",
"luminosity": "30"
},
{
"sensor": "top",
"luminosity": "10"
},
{
"sensor": "right",
"color": "(0,0,0)"
}
]
"###;
let data = serde_json::from_str::<Wrapper>(input).expect("Nope");
let data = data.0;
println!("{:#?}", data);
}
这会产生输出:
{
"left": Data {
luminosity: [
Some("50"),
None,
Some("30")
],
color: [
Some("(255,0,0)"),
Some("#0f0"),
None
]
},
"right": Data {
luminosity: [
Some("20"),
Some("40"),
None
],
color: [
None,
Some("(255,0,0)"),
Some("(0,0,0)")
]
},
"top": Data {
luminosity: [
Some("10")
],
color: [
None
]
}
}