Skip to content

Gale-Shapley implementation in Rust #715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her
- Akash Dhiman
- Vincent Zalzal
- Jonathan D B Van Schenck
- Ishaan Verma
107 changes: 107 additions & 0 deletions contents/stable_marriage_problem/code/rust/stable_marriage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::vec::Vec;
use std::collections::HashMap;
use std::fmt;

#[derive(Hash, Eq, PartialEq, Copy, Clone)]
struct PersonId(pub char);

impl fmt::Display for PersonId {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you want to just derive debug, instead of manually implementing display, to simplify the entire code a bit. Even if you don't want to remove the Display implementation, deriving debug is never a bad practice

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now see that your code relies on the exact representation quite a bit, so then maybe just add a derive debug?

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

#[derive(Clone)]
struct Person {
id: PersonId,
partner: Option<PersonId>,
preferences: Vec<PersonId>,
}

fn gale_shapley(people: Vec<Person>) -> HashMap<PersonId, PersonId> {
let mut stable_matching: HashMap<PersonId, PersonId> = HashMap::new();

for person in people {
let partner = stable_matching
.get(&person.id)
.or_else(|| // execute this if person doesn't have partner
person.preferences
.iter()
// skip all preferences which already have a pair
.skip_while(|id| stable_matching.contains_key(id))
.next()
)
.map(|&id| id);

if let Some(partner) = partner { // set partner
stable_matching.insert(person.id, partner);
stable_matching.insert(partner, person.id);
}
}
stable_matching
}

fn main() {
// create men vector
let men: Vec<Person> = vec![
('A', vec!['E', 'G', 'F', 'H']),
('B', vec!['F', 'H', 'E', 'F']),
('C', vec!['F', 'E', 'H', 'G']),
('D', vec!['E', 'H', 'F', 'G'])
]
.into_iter()
.map(|(id, pref)|
Person {
id: PersonId(id),
partner: None,
preferences: pref.into_iter().map(PersonId).collect(),
}
).collect();

// create women vector
let women: Vec<Person> = vec![
('E', vec!['A', 'D', 'C', 'B']),
('F', vec!['D', 'B', 'A', 'C']),
('G', vec!['D', 'A', 'C', 'B']),
('H', vec!['B', 'A', 'D', 'C'])
]
.into_iter()
.map(|(id, pref)|
Person {
id: PersonId(id),
partner: None,
preferences: pref.into_iter().map(PersonId).collect(),
}
).collect();

let people: Vec<Person> = men.iter().cloned().chain(
women.iter().cloned()).collect();

println!("Men: \n");
for man in &men {
println!("\t{}: {:?}", man.id, man.preferences.clone()
// convert men.preference to vector of chars
.into_iter()
.map(|person| person.0)
.collect::<Vec<char>>());
}
println!("Women: \n");
for woman in &women {
println!("\t{}: {:?}", woman.id, woman.preferences.clone()
// convert women.preference to vector of chars
.into_iter()
.map(|person| person.0)
.collect::<Vec<char>>());
}

let stable_matching: HashMap<PersonId, PersonId> = gale_shapley(people);

// display stable matches
for man in men {
let partner_id = stable_matching.get(&man.id);
match partner_id {
Some(p) => println!("{} + {}", man.id, p),
None => ()
}
}
Comment on lines +100 to +106
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the feeling that iter and .filter_map() might be useful here. (I'm not sure, though.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fanninpm How would we use .filter_map() here? Won't it just over complicate things? We will have to iterate and then collect into vector and then print the vector. I am not sure though. Is there a better way to do this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n1trob4ct3r You can use .for_each() on the iterator, but again, I doubt its usefulness. Besides, you refer to both man.id and partner_id in your solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fanninpm Yes that would be a problem too.

Is there anything else? Is it ready for merging?

}
2 changes: 2 additions & 0 deletions contents/stable_marriage_problem/stable_marriage_problem.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ Here is a video describing the stable marriage problem:
[import, lang:"php"](code/php/stable_marriage.php)
{% sample lang="scala" %}
[import, lang:"scala"](code/scala/stable_marriage.scala)
{% sample lang="rust" %}
[import, lang:"rust"](code/rust/stable_marriage.rs)
{% endmethod %}

<script>
Expand Down