如何将一个结构向量映射或转换为另一个结构向量?

拉斐尔·B·陶伊尔

最小可重复示例

pub struct User {
    pub id: i32,
    pub name: String,
    pub match_id: i32,
}

pub struct Match {
    pub id: i32,
    pub name: String,
}

pub struct MatchWithUsers {
    pub id: i32,
    pub name: String,
    pub users: Vec<User>,
}

fn main() {
    let query_result: Vec<(Match, Option<User>)> = vec![
        (
            Match {
                id: 1,
                name: String::from("1st match"),
            },
            Some(User {
                id: 1,
                name: String::from("Jack"),
                match_id: 1,
            }),
        ),
        (
            Match {
                id: 2,
                name: String::from("2nd match"),
            },
            Some(User {
                id: 2,
                name: String::from("John"),
                match_id: 2,
            }),
        ),
        (
            Match {
                id: 3,
                name: String::from("3rd match"),
            },
            None,
        ),
    ];
    let mut response: Vec<MatchWithUsers> = Vec::new();

    for (m, u) in &query_result {
        let existing_match = &response
            .into_iter()
            .find(|match_with_user| match_with_user.id == m.id);

        match existing_match {
            Some(found_match) => {
                println!("Inser user into match: {}", found_match.name);
                match u {
                    Some(mut user) => {
                        found_match.users.push(user);
                    }
                    None => println!("No users."),
                }
            }
            None => {
                println!("No existing match. Add to response.");
                let user = u.as_ref().unwrap();
                response.push(MatchWithUsers {
                    id: m.id,
                    name: m.name.clone(),
                    users: vec![],
                });
            }
        }
    }

    println!("Response with: {}", response.len());
}
warning: unused variable: `user`
  --> src/main.rs:69:21
   |
69 |                 let user = u.as_ref().unwrap();
   |                     ^^^^ help: consider prefixing with an underscore: `_user`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: variable does not need to be mutable
  --> src/main.rs:61:26
   |
61 |                     Some(mut user) => {
   |                          ----^^^^
   |                          |
   |                          help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0382]: use of moved value: `response`
  --> src/main.rs:53:31
   |
50 |     let mut response: Vec<MatchWithUsers> = Vec::new();
   |         ------------ move occurs because `response` has type `std::vec::Vec<MatchWithUsers>`, which does not implement the `Copy` trait
...
53 |         let existing_match = &response
   |                               ^^^^^^^^ value moved here, in previous iteration of loop

error[E0507]: cannot move out of `u.0` which is behind a shared reference
  --> src/main.rs:60:23
   |
60 |                 match u {
   |                       ^
61 |                     Some(mut user) => {
   |                          --------
   |                          |
   |                          data moved here
   |                          move occurs because `user` has type `User`, which does not implement the `Copy` trait

error[E0596]: cannot borrow `found_match.users` as mutable, as it is behind a `&` reference
  --> src/main.rs:62:25
   |
62 |                         found_match.users.push(user);
   |                         ^^^^^^^^^^^^^^^^^ `found_match` is a `&` reference, so the data it refers to cannot be borrowed as mutable

操场

我的问题

我有一个使用 Rocket 和 Diesel 的 API 测试项目

以下方法执行 Diesel 查询,并将结果映射到 JSON 响应。这是数据库中所有与他们的用户匹配的响应。用户应该嵌套在每个Match节点中。

我的解决方案尝试

  1. 我创建了一个向量。
  2. 在查询结果中迭代;
  3. 检查匹配项是否已存在于我的向量中,如果存在,则添加用户信息(来自查询结果)并将其添加到 current 中的 users 属性MatchWithUser,否则只需MatchWithUsers向向量添加一个 struct ( ) 。
pub fn show_all_matches2() -> Vec<MatchWithUsers> {
    use schema::*;

    let connection = establish_connection();

    let query_result: Vec<(Match, Option<User>)> = matches::table
        .left_join(users::table.on(users::match_id.eq(matches::id)))
        .load(&connection)
        .expect("Error loading matches");

    let mut response: Vec<MatchWithUsers> = Vec::new();

    for (m, u) in &query_result {
        let existing_match = &response
            .into_iter()
            .find(|match_with_user| match_with_user.id == m.id);

        match existing_match {
            Some(mut found_match) => {
                println!("Inser user into match: {}", found_match.name);
                found_match.users.push(u.unwrap());
            }
            None => {
                println!("No existing match. Add to response.");
                let user = u.as_ref().unwrap();
                response.push(MatchWithUsers {
                    id: m.id,
                    name: m.name.clone(),
                    players_count: m.players_count,
                    users: vec![User {
                        id: user.id,
                        name: user.name.clone(),
                        match_id: user.match_id,
                    }],
                });
            }
        }
    }

    response
}

结构

use crate::schema::{matches, users};
use serde::{Deserialize, Serialize};

#[derive(Queryable, Identifiable, Associations, Serialize, Deserialize)]
#[belongs_to(Match)]
#[table_name = "users"]
pub struct User {
    pub id: i32,
    pub name: String,
    pub match_id: i32,
}

#[derive(Queryable, Identifiable, Serialize, Deserialize)]
#[table_name = "matches"]
pub struct Match {
    pub id: i32,
    pub name: String,
    pub players_count: i32,
}

#[derive(Serialize, Deserialize)]
pub struct MatchWithUsers {
    pub id: i32,
    pub name: String,
    pub players_count: i32,
    pub users: Vec<User>,
}

错误

编译时出错

$ cargo run
   Compiling got_board_api_v3 v0.1.0 (/Users/tauil/Projects/got/got-board-api-v3)
error[E0382]: use of moved value: `response`
  --> src/lib.rs:54:31
   |
51 |     let mut response: Vec<MatchWithUsers> = Vec::new();
   |         ------------ move occurs because `response` has type `std::vec::Vec<models::MatchWithUsers>`, which does not implement the `Copy` trait
...
54 |         let existing_match = &response
   |                               ^^^^^^^^ value moved here, in previous iteration of loop

error[E0507]: cannot move out of `existing_match.0` which is behind a shared reference
  --> src/lib.rs:58:15
   |
58 |         match existing_match {
   |               ^^^^^^^^^^^^^^
59 |             Some(mut found_match) => {
   |                  ---------------
   |                  |
   |                  data moved here
   |                  move occurs because `found_match` has type `models::MatchWithUsers`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `*u` which is behind a shared reference
  --> src/lib.rs:61:40
   |
61 |                 found_match.users.push(u.unwrap());
   |                                        ^
   |                                        |
   |                                        move occurs because `*u` has type `std::option::Option<models::User>`, which does not implement the `Copy` trait
   |                                        help: consider borrowing the `Option`'s content: `u.as_ref()`

Postgres客户端查询结果:

select * from matches left join users on matches.id = users.match_id;

 id |        name         | players_count | id |   name    | match_id
----+---------------------+---------------+----+-----------+----------
  1 | My first match      |             3 |  1 | Rafael    |        1
  1 | My first match      |             3 |  2 | Leandro   |        1
  1 | My first match      |             3 |  3 | Vagner    |        1
  2 | Just a second match |             4 |  4 | Vagner    |        2
  2 | Just a second match |             4 |  5 | Leandro   |        2
  2 | Just a second match |             4 |  6 | Rafael    |        2
  2 | Just a second match |             4 |  7 | Wanderson |        2
  3 | Amazing match       |             6 |    |           |
(8 rows)
JMB

如果您使用group_byfrom the itertoolscrate 并确保您的查询结果按匹配 ID 排序,则可以非常轻松地获取与每个匹配项关联的用户的匹配项列表

use itertools::Itertools; // 0.9.0
let response: Vec<_> = query_result
    .into_iter()
    // Note that this assumes that `query_result` is sorted
    // by match id since `group_by` only considers
    // consecutive matches.
    .group_by(|(m, _)| m.id)
    .into_iter()
    .map(|(id, mut g)| {
        // Now `g` is an iterator of `(Match, Option<User>)`
        // where all the matches are the same. We take the
        // first item to get the match information. Note
        // that it is safe to unwrap here because `group_by`
        // would never call us with an empty `g`.
        let (m, u) = g.next().unwrap();
        MatchWithUsers {
            id: id,
            name: m.name,
            // We got the first user along with the match
            // information, now we append the other users
            // from the remaining items in `g`.
            users: u
                .into_iter()
                .chain(g.flat_map(|(_, u)| u.into_iter()))
                .collect(),
        }
    })
    .collect();

操场

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将原子向量转换为另一个向量的类

如何将数据结构转换为另一个树结构

如何将结构添加到来自另一个类的向量?

包含另一个向量的结构向量

将字典结构转换为另一个

C ++更改向量内部,结构内部,另一个向量内部的结构的值

如何使用OpenCV在C ++中将向量的向量结构复制到另一个向量

当一个结构包含另一个结构时,如何在Go中将其转换为另一个结构?

如何将重复的子结构从一个结构复制到另一个结构?

如何将具有向量的XML解析为另一个向量?

这些2D阵列包含结构不同的相同信息。如何将一个转换为另一个?

将结构体指针转换为另一个结构体

如何将数据从一个结构链接到另一个

在 Java 上将一个表结构转换为另一个表结构

如何将一个向量索引位置与另一个向量索引位置匹配?

如何将一个向量复制到另一个向量的末尾?

使用map / reduce函数将一个结构转换为另一个结构

如何在Rust中将一个结构映射到另一个结构?

如何将一个向量添加到另一个拥有第一个向量常量的向量?

从另一个结构中向结构内的向量添加元素

tiki-wiki:如何将一个结构复制到另一个结构或如何复制一个结构

如何将数据从一个结构切片移动到另一个结构?

如何将向量复制到另一个向量的子向量而不会出现段错误?

如何将一个偏函数转换为另一个?

将向量转换为另一个参考系

如何在Go中使用不同的json标签将json从一个结构转换为另一个结构?

如何创建另一个向量的随机向量?

如何将一个结构转换为具有相同成员的另一种类型?

如何通过另一个向量对一个向量的向量进行排序?