这道codewars的prize draw算法题,很有意思,能很好看看rust与众不同的用法。
一、prize draw
资料来源:https://www.codewars.com/kata/prize-draw/solutions/rust
1、26个字母字符按字母表的顺序分别有相应的值,比如A为1,B为2…..,一直到Z:26; 其中大小写不区分。
2、对一个由26个字母字符构成的字符串,字符串对应的值(value)由两部分决定:
(1)字母串的值(val)先由每个字母字符的值相加而得,再加上字符串本身的长度(length)得到字符串值。
(2)字母串最终值由字符串值(val)和赋给的权重(weight)相乘而得。
3、举例
names: COLIN,AMANDBA,AMANDAB,CAROL,PauL,JOSEPH
weights: [1, 4, 4, 5, 2, 1]
对于PauL:
val: = length of Paul + 16 + 1 + 21 + 12 = 4 + 50 -> 54 。
weight: 2;
value = 54 * 2 = 108.
4、对相关的字符对应的value进行降序排列;
5、如果两个字符的value相等,那么,则按字符串的字母顺序进行降序排序:
(1)’a’>’b’>’c’>’d’…….;
(2)如果第一个字母相同,就比第二个字母…..
即,若对于两个都是108的value的字符串进行降序排列的话,就应把第一个字母是’a’的排在是’b’的前面(值大)。
6、给定一个可用”,”切分的字符长串(st),以及对应切分后的字符串的相关weight,请返回按降序排列中第n位的字符。
函数格式:
rank(st: &str, we: Vec, n: usize) -> &str{//
}
其中参数:
st: 如”COLIN,AMANDBA,AMANDAB,CAROL,PauL,JOSEPH” //可以按”,”切分。
we: 如[1, 4, 4, 5, 2, 1]
n: 4
fn main() {
let st = SystemTime::now();
let dd = rank("Addison,Jayden,Sofia,Michael,Andrew,Lily,Benjamin",
vec![4, 2, 1, 4, 3, 1, 2],
4); //返回=>Benjamin
println!("dd,rank:{}", dd);
println!("_sort:{:?} ", sort_str(vec!["aaa", "bbb", "abc"]));
let d1 = rank("Elijah,Chloe,Elizabeth,Matthew,Natalie,Jayden",
vec![1, 3, 5, 5, 3, 6],
2); //返回=> "Matthew");
println!("d1=>{:?}", d1);
let d2 = rank("Aubrey,Olivai,Abigail,Chloe,Andrew,Elizabeth",
vec![3, 1, 4, 4, 3, 2],
4); //返回=>"Abigail");
println!("d2 :{}", d2);
let d3 = rank("Lagon,Lily", vec![1, 5], 2); // 返回=>"Lagon");
println!("d3:{}", d3);
}
7、其它说明:
若st为空,则返回 “No participants”.
若 n> is 切分后字符串的数量,则返回 “Not enough participants”.
二、我的解法
use std::collections::HashMap;
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
if n > st.clone().len() {
return "No participants";
}
let strs: Vec<&str> = st.split(',').collect();
if n > strs.clone().len() {
return "Not enough participants";
}
let scores: Vec<i32> = strs.clone().iter().map(|x| total(x)).collect();
let scores: Vec<i32> = scores.into_iter()
.zip(we.clone().into_iter())
.collect::<Vec<_>>()
.iter()
.map(|x| x.0 * x.1)
.collect();
let mut copy_scores = scores.clone();
copy_scores.sort_by(|a, b| b.cmp(a));
let name_scores: HashMap<&str, i32> =
strs.clone().into_iter().zip(scores.clone().into_iter()).collect();
let len = copy_scores.len();
let copy_strs = strs.clone();
let mut sort_names: Vec<&str> = Vec::new();
for i in 0..len {
let score_i = ©_scores[i];
if i > 0 {
if score_i == ©_scores[i - 1] {
continue;
}
}
let score_i_names: Vec<&str> = copy_strs.clone()
.into_iter()
.filter(|x| name_scores.get(x).unwrap() == score_i)
.collect();
let score_sorted = sort_str(score_i_names);
for sc in score_sorted {
sort_names.push(sc);
}
}
&sort_names[n - 1]
}
fn total(name: &str) -> i32 {
let data: HashMap<char, i32> =
"abcdefghijklmnopqrstuvwxyz".chars().enumerate().map(|(x, y)| (y, x as i32 + 1)).collect();
name.to_lowercase().chars().fold(0, |total, x| total + data.get(&x).unwrap()) +
name.len() as i32
}
fn sort_str<'a>(names: Vec<&'a str>) -> Vec<&'a str> {
let n: usize = names.len();
let mut _names = names.clone();
for i in 0..n - 1 {
for j in i + 1..n {
let (na, _) = _sort_by(names.clone().get(i).unwrap(),
names.clone().get(j).unwrap(),
0);
if &na != names.clone().get(i).unwrap() {
_names = _sort(_names, i, j);
}
}
}
_names
}
fn _sort<'a>(names: Vec<&'a str>, n: usize, m: usize) -> Vec<&'a str> {
let mut _names = names;
let nval: &'a str = _names.clone().get(n).unwrap();
let mval: &'a str = _names.clone().get(m).unwrap();
if let Some(elem) = _names.get_mut(n) {
*elem = mval;
}
if let Some(elem) = _names.get_mut(m) {
*elem = nval;
}
_names
}
fn _sort_by<'a>(name1: &'a str, name2: &'a str, n: usize) -> (&'a str, &'a str) {
let n1 = name1.len();
let n2 = name2.len();
let min_n = match n1 < n2 {
true => n1,
_ => n2,
};
if n > min_n - 1 {
return (&name1, &name2);
} else {
if &name1.chars().nth(n) < &name2.chars().nth(n) {
(&name1, &name2)
} else if &name1.chars().nth(n) == &name2.chars().nth(n) {
if n == min_n {
return (&name1, &name2);
}
_sort_by(name1, name2, n + 1)
} else {
(&name2, &name1)
}
}
}
三、其它精彩的解法
1、
fn letter_values(value: &str) -> i32 {
let charactor_total: i32 = value
.chars()
.map(|x| x.to_digit(36).unwrap_or(0) as i32)
.map(|x| x - 9)
.sum();
charactor_total + (value.len() as i32)
}
fn rank_names(st: &str, we: Vec<i32>) -> Vec<(i32, &str)> {
let names = st.split(',');
let mut raffles = names
.clone()
.into_iter()
.map(|x| String::from(x))
.zip(we)
.map(|(left, right)| letter_values(&left) * (right))
.zip(names)
.collect::<Vec<(i32, &str)>>();
raffles.sort_by(|&(_, a), &(_, b)| a.cmp(&b));
raffles.sort_by(|&(a, _), &(b, _)| b.cmp(&a));
raffles
}
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
let raffles = rank_names(&st, we);
if st.len() == 0 {
return "No participants";
}
let (_, winning_name) = raffles.into_iter().nth(n - 1).unwrap_or((0, "Not enough participants"));
&winning_name
}
2、
const A_BYTE: u16 = 'a' as u16;
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
if st.is_empty() { return "No participants"; }
let participants = st.split(',').collect::<Vec<_>>();
if n > participants.len() { return "Not enough participants"; }
let mut winning_numbers_vec = participants.into_iter().zip(we).map(winning_number).collect::<Vec<_>>();
let winning_numbers = winning_numbers_vec.as_mut_slice();
winning_numbers.sort();
let (_, name) = winning_numbers[n-1];
name
}
fn winning_number(pair: (&str,i32)) -> (i32,&str) {
let (name, weight) = pair;
let n =
name.to_lowercase() //Case insensitive
.into_bytes() //ASCII code
.into_iter().map(|byte| byte as u16 - A_BYTE + 1) //Alphabet order
.fold(name.len() as u16, |n, value| n + value); //Sum values
(n as i32 * -weight, name)
}
3、
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
if st.len() == 0 {
return "No participants";
}
let names = st
.split(',')
.collect::<Vec<&str>>()
;
if n > names.len() {
return "Not enough participants";
}
let mut sorted = names
.iter()
.map(|name| name
.to_lowercase()
.bytes()
.map(|byte| byte as usize - 96)
.collect::<Vec<usize>>()
)
.map(|vector| vector.len() + vector.iter().sum::<usize>())
.zip(we)
.map(|(number, weight)| number * weight as usize)
.zip(names.clone())
.collect::<Vec<(usize, &str)>>()
;
sorted.sort_by_key(|&(_, n)| n.to_lowercase());
sorted.sort_by_key(|&(w, _)| -(w as isize));
sorted[n-1].1
}
4、
fn word_rank(w: &str) -> usize {
w.len() + w.to_lowercase().chars().map(|c| c as usize - 96).sum::<usize>()
}
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
let ws: Vec<&str> = st.split(',').filter(|s| s.len() > 0).collect();
if ws.len() == 0 {
return "No participants";
}
if n > ws.len() {
return "Not enough participants";
}
let vs: Vec<_> = ws.iter().map(|w| word_rank(w))
.zip(we.iter()).map(|(a, &b)| a * (b as usize)).collect();
let mut rk: Vec<_> = (0..ws.len()).collect();
// rk.sort_by(|&i, &j| vs[j].cmp(&vs[i]).then(ws[i].cmp(ws[j])));
rk.sort_by(|&i, &j| {
let r = vs[j].cmp(&vs[i]);
if r == std::cmp::Ordering::Equal {ws[i].cmp(ws[j])} else {r}
});
ws[rk[n-1]]
}
6、
static RANKS: &'static str = "abcdefghijklmnopqrstuvwxyz";
fn rank(st: &str, we: Vec<i32>, n: usize) -> &str {
if st.is_empty() { return "No participants"; }
let names: Vec<&str> = st.split(",").collect();
if n > names.len() { return "Not enough participants"; }
let mut name_ranks: Vec<(i32, &str)> = names.iter().zip(we).map(|(&name, weight)| {
let winning_number = weight * name.to_lowercase().chars().fold(name.len(), |sum, x| sum + RANKS.chars().position(|y| y == x).unwrap() + 1) as i32;
(-winning_number, name)
}).collect();
name_ranks.sort();
name_ranks[n-1].1
}