Peter Norvigs Spellcheck en Rust -- strings campo con rust camp codereview Relacionados El problema

Peter Norvigs spellcheck in Rust


4
vote

problema

Español

Para un proyecto de óxido en el que estoy trabajando en la que necesitaba un (simple) algoritmo de hechicencia y me propuse re-implementar Peter Norvigs SpellCheck algoritmo en óxido.

  import java.util.Optional; import java.util.Scanner;  public class Calculator {      public static final String EXIT_MESSAGE = "Okay! Nobody misses you" +             "  But here's the calculations you've done so far";     private static final String WRONG_ACTION_MESSAGE = "Shit, wrong answer,  you'll have to calculate " +             "with these numbers again and then you can do whatever you want";     private HistoryHolder historyHolder = new HistoryHolder();     private Solver solver;     private Scanner scanner;      private AskForAction askForAction;     private AskForNumber askForFirstNumber;     private AskForNumber askForSecondNumber;     private AskForOperation askForOperation;     private double firstNumber;     private double secondNumber;      public Calculator(Solver solver, Scanner scanner) {         this.scanner = scanner;         this.solver = solver;         initializeAskers();     }      private void initializeAskers() {         askForAction = new AskForAction(this.scanner);         askForFirstNumber = new AskForNumber("Input the 1st number", this.scanner);         askForSecondNumber = new AskForNumber("Input the 2nd number", this.scanner);         askForOperation = new AskForOperation(this.scanner);     }      public void run() {         askUsersUnitialNumbers();         Action action;         do {             Expression expression = buildExpression();             processExpression(expression);             action = askAndVerifyAction();             if (action.isChangeNumbers()) {                 askUsersUnitialNumbers();             }         } while (!action.isStopCondition());         endProgram();     }      private void askUsersUnitialNumbers() {         firstNumber = askForFirstNumber.ask();         secondNumber = askForSecondNumber.ask();     }      private Expression buildExpression() {          char operator = askForOperation.ask();          return Expression.Builder.anExpression()                 .firstNumber(firstNumber)                 .secondNumber(secondNumber)                 .operator(operator).build();     }      private void endProgram() {         printExitMessage();         printHistory();     }      private Action askAndVerifyAction() {         Optional<Action> possibleAction = askForAction.ask();         verifyPossibleAction(possibleAction);         return possibleAction.get();     }      private void verifyPossibleAction(Optional<Action> possibleAction) {         if (!possibleAction.isPresent()) {             showWrongActionMessage();         }     }       private void processExpression(Expression expression) {         Optional<Double> possibleResult = solver.solveExpression(expression);          printResult(possibleResult);         addToHistory(possibleResult);     }       private void showWrongActionMessage() {         System.out.println(WRONG_ACTION_MESSAGE);     }      private void printExitMessage() {         System.out.println(EXIT_MESSAGE);     }      private void addToHistory(Optional<Double> pretendResult) {         if (pretendResult.isPresent()) {             historyHolder.add(pretendResult.get());         }     }      private void printResult(Optional<Double> pretendResult) {         if (pretendResult.isPresent()) {             System.out.println(pretendResult.get());         }     }      private void printHistory() {         historyHolder.printHistory();     }  } 5  

La salida es:

  import java.util.Optional; import java.util.Scanner;  public class Calculator {      public static final String EXIT_MESSAGE = "Okay! Nobody misses you" +             "  But here's the calculations you've done so far";     private static final String WRONG_ACTION_MESSAGE = "Shit, wrong answer,  you'll have to calculate " +             "with these numbers again and then you can do whatever you want";     private HistoryHolder historyHolder = new HistoryHolder();     private Solver solver;     private Scanner scanner;      private AskForAction askForAction;     private AskForNumber askForFirstNumber;     private AskForNumber askForSecondNumber;     private AskForOperation askForOperation;     private double firstNumber;     private double secondNumber;      public Calculator(Solver solver, Scanner scanner) {         this.scanner = scanner;         this.solver = solver;         initializeAskers();     }      private void initializeAskers() {         askForAction = new AskForAction(this.scanner);         askForFirstNumber = new AskForNumber("Input the 1st number", this.scanner);         askForSecondNumber = new AskForNumber("Input the 2nd number", this.scanner);         askForOperation = new AskForOperation(this.scanner);     }      public void run() {         askUsersUnitialNumbers();         Action action;         do {             Expression expression = buildExpression();             processExpression(expression);             action = askAndVerifyAction();             if (action.isChangeNumbers()) {                 askUsersUnitialNumbers();             }         } while (!action.isStopCondition());         endProgram();     }      private void askUsersUnitialNumbers() {         firstNumber = askForFirstNumber.ask();         secondNumber = askForSecondNumber.ask();     }      private Expression buildExpression() {          char operator = askForOperation.ask();          return Expression.Builder.anExpression()                 .firstNumber(firstNumber)                 .secondNumber(secondNumber)                 .operator(operator).build();     }      private void endProgram() {         printExitMessage();         printHistory();     }      private Action askAndVerifyAction() {         Optional<Action> possibleAction = askForAction.ask();         verifyPossibleAction(possibleAction);         return possibleAction.get();     }      private void verifyPossibleAction(Optional<Action> possibleAction) {         if (!possibleAction.isPresent()) {             showWrongActionMessage();         }     }       private void processExpression(Expression expression) {         Optional<Double> possibleResult = solver.solveExpression(expression);          printResult(possibleResult);         addToHistory(possibleResult);     }       private void showWrongActionMessage() {         System.out.println(WRONG_ACTION_MESSAGE);     }      private void printExitMessage() {         System.out.println(EXIT_MESSAGE);     }      private void addToHistory(Optional<Double> pretendResult) {         if (pretendResult.isPresent()) {             historyHolder.add(pretendResult.get());         }     }      private void printResult(Optional<Double> pretendResult) {         if (pretendResult.isPresent()) {             System.out.println(pretendResult.get());         }     }      private void printHistory() {         historyHolder.printHistory();     }  } 6  

que parece estar aproximadamente en línea con lo que hace Peters Python Version.

El código es básicamente corredor, pero debe tener el archivo import java.util.Optional; import java.util.Scanner; public class Calculator { public static final String EXIT_MESSAGE = "Okay! Nobody misses you" + " But here's the calculations you've done so far"; private static final String WRONG_ACTION_MESSAGE = "Shit, wrong answer, you'll have to calculate " + "with these numbers again and then you can do whatever you want"; private HistoryHolder historyHolder = new HistoryHolder(); private Solver solver; private Scanner scanner; private AskForAction askForAction; private AskForNumber askForFirstNumber; private AskForNumber askForSecondNumber; private AskForOperation askForOperation; private double firstNumber; private double secondNumber; public Calculator(Solver solver, Scanner scanner) { this.scanner = scanner; this.solver = solver; initializeAskers(); } private void initializeAskers() { askForAction = new AskForAction(this.scanner); askForFirstNumber = new AskForNumber("Input the 1st number", this.scanner); askForSecondNumber = new AskForNumber("Input the 2nd number", this.scanner); askForOperation = new AskForOperation(this.scanner); } public void run() { askUsersUnitialNumbers(); Action action; do { Expression expression = buildExpression(); processExpression(expression); action = askAndVerifyAction(); if (action.isChangeNumbers()) { askUsersUnitialNumbers(); } } while (!action.isStopCondition()); endProgram(); } private void askUsersUnitialNumbers() { firstNumber = askForFirstNumber.ask(); secondNumber = askForSecondNumber.ask(); } private Expression buildExpression() { char operator = askForOperation.ask(); return Expression.Builder.anExpression() .firstNumber(firstNumber) .secondNumber(secondNumber) .operator(operator).build(); } private void endProgram() { printExitMessage(); printHistory(); } private Action askAndVerifyAction() { Optional<Action> possibleAction = askForAction.ask(); verifyPossibleAction(possibleAction); return possibleAction.get(); } private void verifyPossibleAction(Optional<Action> possibleAction) { if (!possibleAction.isPresent()) { showWrongActionMessage(); } } private void processExpression(Expression expression) { Optional<Double> possibleResult = solver.solveExpression(expression); printResult(possibleResult); addToHistory(possibleResult); } private void showWrongActionMessage() { System.out.println(WRONG_ACTION_MESSAGE); } private void printExitMessage() { System.out.println(EXIT_MESSAGE); } private void addToHistory(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { historyHolder.add(pretendResult.get()); } } private void printResult(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { System.out.println(pretendResult.get()); } } private void printHistory() { historyHolder.printHistory(); } } 7 que contiene palabras de varias fuentes de texto combinadas en un blob. El archivo se puede encontrar aquí (¡tenga cuidado: 6,5 MB de archivo de texto por delante!)

  • Refactore Ya el import java.util.Optional; import java.util.Scanner; public class Calculator { public static final String EXIT_MESSAGE = "Okay! Nobody misses you" + " But here's the calculations you've done so far"; private static final String WRONG_ACTION_MESSAGE = "Shit, wrong answer, you'll have to calculate " + "with these numbers again and then you can do whatever you want"; private HistoryHolder historyHolder = new HistoryHolder(); private Solver solver; private Scanner scanner; private AskForAction askForAction; private AskForNumber askForFirstNumber; private AskForNumber askForSecondNumber; private AskForOperation askForOperation; private double firstNumber; private double secondNumber; public Calculator(Solver solver, Scanner scanner) { this.scanner = scanner; this.solver = solver; initializeAskers(); } private void initializeAskers() { askForAction = new AskForAction(this.scanner); askForFirstNumber = new AskForNumber("Input the 1st number", this.scanner); askForSecondNumber = new AskForNumber("Input the 2nd number", this.scanner); askForOperation = new AskForOperation(this.scanner); } public void run() { askUsersUnitialNumbers(); Action action; do { Expression expression = buildExpression(); processExpression(expression); action = askAndVerifyAction(); if (action.isChangeNumbers()) { askUsersUnitialNumbers(); } } while (!action.isStopCondition()); endProgram(); } private void askUsersUnitialNumbers() { firstNumber = askForFirstNumber.ask(); secondNumber = askForSecondNumber.ask(); } private Expression buildExpression() { char operator = askForOperation.ask(); return Expression.Builder.anExpression() .firstNumber(firstNumber) .secondNumber(secondNumber) .operator(operator).build(); } private void endProgram() { printExitMessage(); printHistory(); } private Action askAndVerifyAction() { Optional<Action> possibleAction = askForAction.ask(); verifyPossibleAction(possibleAction); return possibleAction.get(); } private void verifyPossibleAction(Optional<Action> possibleAction) { if (!possibleAction.isPresent()) { showWrongActionMessage(); } } private void processExpression(Expression expression) { Optional<Double> possibleResult = solver.solveExpression(expression); printResult(possibleResult); addToHistory(possibleResult); } private void showWrongActionMessage() { System.out.println(WRONG_ACTION_MESSAGE); } private void printExitMessage() { System.out.println(EXIT_MESSAGE); } private void addToHistory(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { historyHolder.add(pretendResult.get()); } } private void printResult(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { System.out.println(pretendResult.get()); } } private void printHistory() { historyHolder.printHistory(); } } 8 , import java.util.Optional; import java.util.Scanner; public class Calculator { public static final String EXIT_MESSAGE = "Okay! Nobody misses you" + " But here's the calculations you've done so far"; private static final String WRONG_ACTION_MESSAGE = "Shit, wrong answer, you'll have to calculate " + "with these numbers again and then you can do whatever you want"; private HistoryHolder historyHolder = new HistoryHolder(); private Solver solver; private Scanner scanner; private AskForAction askForAction; private AskForNumber askForFirstNumber; private AskForNumber askForSecondNumber; private AskForOperation askForOperation; private double firstNumber; private double secondNumber; public Calculator(Solver solver, Scanner scanner) { this.scanner = scanner; this.solver = solver; initializeAskers(); } private void initializeAskers() { askForAction = new AskForAction(this.scanner); askForFirstNumber = new AskForNumber("Input the 1st number", this.scanner); askForSecondNumber = new AskForNumber("Input the 2nd number", this.scanner); askForOperation = new AskForOperation(this.scanner); } public void run() { askUsersUnitialNumbers(); Action action; do { Expression expression = buildExpression(); processExpression(expression); action = askAndVerifyAction(); if (action.isChangeNumbers()) { askUsersUnitialNumbers(); } } while (!action.isStopCondition()); endProgram(); } private void askUsersUnitialNumbers() { firstNumber = askForFirstNumber.ask(); secondNumber = askForSecondNumber.ask(); } private Expression buildExpression() { char operator = askForOperation.ask(); return Expression.Builder.anExpression() .firstNumber(firstNumber) .secondNumber(secondNumber) .operator(operator).build(); } private void endProgram() { printExitMessage(); printHistory(); } private Action askAndVerifyAction() { Optional<Action> possibleAction = askForAction.ask(); verifyPossibleAction(possibleAction); return possibleAction.get(); } private void verifyPossibleAction(Optional<Action> possibleAction) { if (!possibleAction.isPresent()) { showWrongActionMessage(); } } private void processExpression(Expression expression) { Optional<Double> possibleResult = solver.solveExpression(expression); printResult(possibleResult); addToHistory(possibleResult); } private void showWrongActionMessage() { System.out.println(WRONG_ACTION_MESSAGE); } private void printExitMessage() { System.out.println(EXIT_MESSAGE); } private void addToHistory(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { historyHolder.add(pretendResult.get()); } } private void printResult(Optional<Double> pretendResult) { if (pretendResult.isPresent()) { System.out.println(pretendResult.get()); } } private void printHistory() { historyHolder.printHistory(); } } 9 , 9988777665544332020 , import java.util.Arrays; import java.util.Optional; public enum Action { DO_MORE_CALCULATIONS(1), EXIT_AND_PRINT_HISTORY(2), CHANGE_NUMBERS(3); private int actionNumber; Action(int actionNumber) { this.actionNumber = actionNumber; } public static Optional<Action> byActionNumber(int actionNumber) { return Arrays.stream(values()) .filter(action -> action.actionNumber == actionNumber) .findFirst(); } public boolean isStopCondition() { return this == EXIT_AND_PRINT_HISTORY; } public boolean isChangeNumbers() { return this == CHANGE_NUMBERS; } } 1 Funciones gracias a Otro código Revisión aquí .
  • En general me interesaría si obtuviera la propiedad correcta. Sin embargo, luché con menos con el corrector prestado esta vez.
  • Hay una línea en la función import java.util.Arrays; import java.util.Optional; public enum Action { DO_MORE_CALCULATIONS(1), EXIT_AND_PRINT_HISTORY(2), CHANGE_NUMBERS(3); private int actionNumber; Action(int actionNumber) { this.actionNumber = actionNumber; } public static Optional<Action> byActionNumber(int actionNumber) { return Arrays.stream(values()) .filter(action -> action.actionNumber == actionNumber) .findFirst(); } public boolean isStopCondition() { return this == EXIT_AND_PRINT_HISTORY; } public boolean isChangeNumbers() { return this == CHANGE_NUMBERS; } } 6655443322 es un desagradable, hace una asignación de cadena cada vez que se comprueba si la tecla está en el import java.util.Arrays; import java.util.Optional; public enum Action { DO_MORE_CALCULATIONS(1), EXIT_AND_PRINT_HISTORY(2), CHANGE_NUMBERS(3); private int actionNumber; Action(int actionNumber) { this.actionNumber = actionNumber; } public static Optional<Action> byActionNumber(int actionNumber) { return Arrays.stream(values()) .filter(action -> action.actionNumber == actionNumber) .findFirst(); } public boolean isStopCondition() { return this == EXIT_AND_PRINT_HISTORY; } public boolean isChangeNumbers() { return this == CHANGE_NUMBERS; } } 3 pero lo pone solo una vez.
  • El rendimiento está bien para mi usecase pero no es realmente impresionante.

Todos los demás comentarios / sugerencias son bienvenidos, por supuesto.

My Usecase es solo sobre las cadenas ASCII. Pensé en usar el import java.util.Arrays; import java.util.Optional; public enum Action { DO_MORE_CALCULATIONS(1), EXIT_AND_PRINT_HISTORY(2), CHANGE_NUMBERS(3); private int actionNumber; Action(int actionNumber) { this.actionNumber = actionNumber; } public static Optional<Action> byActionNumber(int actionNumber) { return Arrays.stream(values()) .filter(action -> action.actionNumber == actionNumber) .findFirst(); } public boolean isStopCondition() { return this == EXIT_AND_PRINT_HISTORY; } public boolean isChangeNumbers() { return this == CHANGE_NUMBERS; } } 6655443324 Tipos de cajas para hacer eso explícito, pero no en esta versión, es una sugerencia justa, por supuesto.

Original en ingles

For a Rust project I'm working on I needed a (simple) spellcheck algorithm and I set out to re-implement Peter Norvigs spellcheck algorithm in Rust.

extern crate regex;  use regex::Regex;  use std::collections::HashMap; use std::collections::HashSet; use std::iter::FromIterator; use std::path::Path; use std::io::prelude::*; use std::fs::File;  static ALPHABET : &'static str = "abcdefghijklmnopqrstuvwxyz";  fn deletes(s: &str) -> Vec<String> {     (0..s.len())         .map(|i| {             let mut delete = s.to_owned();             delete.remove(i);              delete         })         .collect() }  fn inserts(s: &str) -> Vec<String> {     (0..s.len() + 1)         .flat_map(|i| {             ALPHABET.chars().map(|chr| {                 let mut insert = s.to_owned();                 insert.insert(i, chr);                  insert             }).collect::<Vec<_>>()         })         .collect() }  fn replaces(s: &str) -> Vec<String> {     (0..s.len())         .flat_map(|i| {             ALPHABET.chars().map(|chr| {                 let mut replace = String::with_capacity(s.len());                 replace.push_str(&s[0..i]);                 replace.push(chr);                 replace.push_str(&s[i + 1..]);                  replace             }).collect::<Vec<_>>()         })         .collect() }  fn transposes(s: &str) -> Vec<String> {     let bytes = s.as_bytes();      (1..bytes.len())         .map(|i| {             let mut transpose = bytes.to_owned();             transpose.swap(i - 1, i);              String::from_utf8(transpose).expect("Invalid UTF-8")         })         .collect() }  fn read_dictionary_words(dictionary_path: &str) -> String {     let mut buffer = String::new();      File::open(&Path::new(dictionary_path))         .unwrap()         .read_to_string(&mut buffer)         .unwrap();      buffer }  fn word_count(all_words: &str) ->  HashMap<String, u32> {     let re = Regex::new(r"\w+").unwrap();     let lowercase = all_words.to_lowercase();      let mut map = HashMap::new();      for word in re.captures_iter(&lowercase) {         // arg, the to_owned is pretty nasty here, as it creates a new owned string every time ...         *map.entry(word[0].to_owned()).or_insert(0) += 1;     }      map }  fn edits1(s: &str) -> HashSet<String> {     deletes(s)         .into_iter()         .chain(replaces(s).into_iter())         .chain(transposes(s).into_iter())         .chain(inserts(s).into_iter())         .collect() }  fn edits2(s: &str) -> HashSet<String> {     edits1(s)         .iter()         .flat_map(|e| edits1(e))         .collect() }  fn calc_p(word: &str, wc: &HashMap<String, u32>) -> f32 {     if !wc.contains_key(word) {         return 0.0;     }      let total:u32 = wc.values().sum();     wc[word] as f32 / total as f32 }  fn known(candidates: HashSet<String>, wc: &HashMap<String, u32>) -> HashSet<String> {     candidates         .into_iter()         .filter(|w| wc.contains_key(w))         .collect::<HashSet<_>>() }  fn create_candidates(s: &str, wc: &HashMap<String, u32>) -> HashSet<String> {     if wc.contains_key(s) {         return HashSet::from_iter(vec![s.to_owned()].into_iter());     }      let candidates = known(edits1(s), wc);      if candidates.len() > 0 {         return candidates;     }      let candidates = known(edits2(s), wc);      if candidates.len() > 0 {         return candidates;     }      HashSet::new() }  fn correction(candidates: HashSet<String>, wc: &HashMap<String, u32>) -> Vec<(f32, String)> {     let mut weighted_candidates = candidates         .into_iter()         .map(|w| (calc_p(&w, &wc), w))         .collect::<Vec<_>>();      weighted_candidates.sort_by(|a, b| b.partial_cmp(a).unwrap());      weighted_candidates }  fn main() {     // This is the file from http://www.norvig.com/big.txt     let all_words = read_dictionary_words("/tmp/big.txt");     let wc = word_count(&all_words);      let corrections = correction(create_candidates("speling", &wc), &wc);     println!("{:?}", corrections.first().unwrap());      let corrections = correction(create_candidates("korrectud", &wc), &wc);     println!("{:?}", corrections.first().unwrap()); } 

The output is:

(0.0000035855628, "spelling") // suggestion for "speling" (0.00001254947, "corrected")  // suggestion for "korrectud" 

Which seems to be roughly in line with what Peters Python version does.

The code is basically runnable, but you need to have the file big.txt which contains words from various text sources combined into one blob. The file can be found here (BEWARE: 6.5 MB text file ahead!)

  • I refactored already the deletes, transposes, inserts, replaces functions thanks to another code review here.
  • In general I would be interested if I got ownership right. I fought less with the borrow checker this time however.
  • There is a line in the word_count function that's particular nasty, it does a string allocation every time for checking if the key is in the HashMap but puts it in only once.
  • The performance is OK for my usecase but not really impressive.

All other comments/suggestions are welcome, too, of course.

My usecase is only about ASCII strings. I thought about using the ASCII crate types to make that explicit, but not in this version, it's a fair suggestion of course.

     

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

Algunos comentarios, ya que nadie más ha publicado aquí:

Configure un manejo adecuado de errores para que no tenga tantos unwraps y expects . Creo que el error_chain es la forma recomendada / la más popular de manejar el manejo de errores, pero es probable que sea exagerado para su caso. Sin embargo, error_chain3 también proporciona la macro 998877766655443344 , que le permite definir fácilmente sus propios errores y envolver errores externos. Para el manejo muy, muy básico, puede hacerlo:

  pub mod err {     quick_error! {         #[derive(Debug)]         pub enum Error {             Other(err: Box<::std::error::Error + Send + Sync>) {                 from(e: &'static str) -> (e.into())                 from(e: ::std::io::Error) -> (e.into())                                 description(err.description())                 display("{}", err)             }             }     }     pub type Result<T> = ::std::result::Result<T, Error>; }   

y luego envuelva sus funciones en Result<_> , y puede usar try / ? en todas partes.


No es realmente un gran problema para su caso, ya que solo lo llamaste una vez, pero es una buena práctica envolver Regex::new en 99887776655443310 para evitar compilarlo varias veces, por ejemplo:
  expects1  


Puede trabajar alrededor de la asignación de cadena con la API de entrada (no está segura de si hay una manera más elegante de hacer esto ...):
  expects2  


Sugeriría devolver un expects3
expects4 de expects5 Donde devuelve un 99887776655443316 como tipo, para que No tiene que comprobar expects7 varias veces en expects8 . Puede encapare los diferentes candidatos, luego devuelva el valor predeterminado si no se aplica ninguno.
¡ADEMÁS! Si su rendimiento parece estar mal, asegúrese de que está haciendo expects9 o error_chain0 para ejecutar su programa.

Espero que esto ayude,

 

A few comments, since no one else has posted here:

Set up some proper error handling so you don't have so many unwraps and expects. I think the error_chain crate is the recommended/most popular way to do error handling, but is probably overkill for your case. However, error_chain also provides the quick_error macro, which allows you to easily define your own errors and wrap external errors. For very, very basic handling you can just do:

pub mod err {     quick_error! {         #[derive(Debug)]         pub enum Error {             Other(err: Box<::std::error::Error + Send + Sync>) {                 from(e: &'static str) -> (e.into())                 from(e: ::std::io::Error) -> (e.into())                                 description(err.description())                 display("{}", err)             }             }     }     pub type Result<T> = ::std::result::Result<T, Error>; } 

And then wrap your functions in Result<_>, and you can use try/? everywhere.


Not really a big deal for your case since you only call it once, but it is good practice to wrap Regex::new in lazy_static to avoid compiling it multiple times, e.g.:
lazy_static! {     static ref RE: Regex = Regex::new(r"\w+").unwrap(); } 


You can work around the String allocation with the Entry API like (not sure if there is a more graceful way to do this...):
for word in re.captures_iter(&lowercase) {     let word0 = word[0];     if let Some(e) = map.get_mut(word0) {         *e += 1;         continue;     }     map.insert(word0.into(), 1); } 


I would suggest returning an Option or Result from known where the empty case returns a None like type, so that you don't have to check candidates.len() > 0 multiple times in create_candidates. You could chain the different candidates then return the default if none apply.
ALSO! If your performance seems bad, make sure that you are doing cargo run --release or cargo build --release to run your program.

Hope this helpsxe2x80x94

 
 
 
 

Relacionados problema

8  Reemplace la cadena en el archivo  ( Replace string in file ) 
Este es mi primer módulo que escribí en el óxido. Soy nuevo en el idioma y no pude encontrar una manera de reemplazar fácilmente algunas palabras en un archiv...

7  HMAC con SHA256 / 512 en óxido  ( Hmac with sha256 512 in rust ) 
He intentado lo mejor que puedo, para implementar HMAC como se especifica en la RFC 2104 < / a>. Este es también mi primer proyecto de óxido, por lo que las ...

3  Aplicación singularidad e IPC unilateral en UNIX  ( Application uniqueness and unilateral ipc on unix ) 
este programa Detecta la singularidad de la aplicación, si la aplicación es una instancia única / primaria, lanza un servidor, de lo contrario, un cliente...

6  Utilidad X-up para EVE Online  ( X up utility for eve online ) 
Estoy aprendiendo a Rust. También interpreto a Eve Online: un videojuego sobre las naves espaciales de Internet. Decidí que sería divertido practicar el óxi...

3  Lista doblemente vinculada en óxido usando los punteros crudos  ( Doubly linked list in rust using raw pointers ) 
Estoy practicando la oxidación escribiendo una lista doblemente vinculada usando los punteros crudos, 9988776655544330 Para asignar datos en el montón, 998...

6  Clasificación de palabras por frecuencia  ( Sorting words by frequency ) 
Estoy haciendo una tarea simple en óxido después de leer el Libro de óxido : Lea un archivo de texto dividirlo en Whitespace desinfectar palabras elim...

5  Canción de 99 cervezas en óxido  ( 99 beers song in rust ) 
Estoy aprendiendo a Rust. Me parece que a veces se confuso en comparación con otros lenguajes de programación, especialmente cuando se trata de cadenas y re...

7  Implementar una secuencia de Fibonacci genérica en óxido sin usar copia rasgo  ( Implement a generic fibonacci sequence in rust without using copy trait ) 
Estoy tratando de aprender a óxido y soy un principiante. ¿Cómo se hace frente a la implementación de una versión genérica de la secuencia FIBONACCI sin usar ...

3  Base64 String ↔ Array flotante  ( Base64 string %e2%86%94 float array ) 
Necesito convertir move constructor8 matrices con una longitud de fix a base64 Representación y atrás. Mi código actual se ve así. Funciona, pero se sient...

1  La mejor implementación de la mejor búsqueda de primera búsqueda en óxido  ( Greedy best first search implementation in rust ) 
He implementado un codicioso algoritmo de primera búsqueda en Rust, ya que no pude encontrar una ya implementada en las cajas existentes. Tengo un pequeño pro...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos