The Ducci Sequence
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
6
down vote
favorite
I wrote the following Rust code to solve this task on /r/DailyProgrammer.
Given an n-tuple of numbers as input, the Ducci Sequence is formed by
taking the absolute difference of the difference between neighboring
elements. (The last result is the difference between the first and
last elements.)
Example input
[0; 653; 1854; 4063]
Example output
Emit the number of steps taken to get to either an all 0 tuple or when
it enters a stable repeating pattern.[0; 653; 1854; 4063]
[653; 1201; 2209; 4063]
[548; 1008; 1854; 3410]
[460; 846; 1556; 2862]
[386; 710; 1306; 2402]
[324; 596; 1096; 2016]
[272; 500; 920; 1692]
[228; 420; 772; 1420]
[192; 352; 648; 1192]
[160; 296; 544; 1000]
[136; 248; 456; 840]
[112; 208; 384; 704]
[96; 176; 320; 592]
[80; 144; 272; 496]
[64; 128; 224; 416]
[64; 96; 192; 352]
[32; 96; 160; 288]
[64; 64; 128; 256]
[0; 64; 128; 192]
[64; 64; 64; 192]
[0; 0; 128; 128]
[0; 128; 0; 128]
[128; 128; 128; 128]
[0; 0; 0; 0]
24 steps
I'm aware all the extra functions and error handling are a bit exaggerated for a task this easy, but I'm learning rust at the moment so I tried to get things right.
extern crate regex;
use std::io::Write;
use std::fmt::Display;
use std::fmt;
use regex::Regex;
use std::io;
use std::error;
fn main()
match read_input()
Ok(tuple) =>
run(tuple);
Err(e) =>
eprintln!("An error occured: ", e);
/// Tries to read input from standard input
fn read_input() -> Result<Tuple, Error>
print!("input: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Tuple::new(input)
/// runs Ducci sequence calculation and prints every step
fn run(tuple: Tuple)
let mut i = tuple;
let mut history: Vec<Tuple> = Vec::new();
let mut steps = 1;
while !&i.zeros() && !history.contains(&i)
let next = i.next();
history.push(i);
i = next;
println!("", i);
steps += 1;
println!(" steps", steps);
struct Tuple
data: Vec<i32>,
impl Tuple
fn new(line: String) -> Result<Tuple, Error>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line.as_str())
Err(Error::ParsingError)
else
// seperate single numbers, parse to integer and push into tuple instance
let sep = Regex::new(r"(,
/// Calculates and returns next tuple in ducci sequence
fn next(&self) -> Tuple
let mut data: Vec<i32> = Vec::new();
// calculate first n - 1 new values
for i in 0..self.dimension() - 1
data.push((self.data[i] - self.data[i + 1]).abs());
// calculate last value
data.push((self.data[self.dimension() - 1] - self.data[0]).abs());
Tuple
data: data,
/// Returns tuples dimension
fn dimension(&self) -> usize
self.data.len()
/// Determines whether tuple only contains zeros
fn zeros(&self) -> bool
self.data.iter().fold(true,
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
let mut e = true;
for i in 0..self.dimension()
e = e && self.data[i] == other.data[i];
e
impl Display for Tuple
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
let mut s = String::new();
s.push_str("[");
for i in 0..self.dimension() - 1
s.push_str(self.data[i].to_string().as_str());
s.push_str("; ");
s.push_str(self.data[self.dimension() - 1].to_string().as_str());
s.push_str("]");
write!(f, "", s)
#[derive(Debug)]
enum Error
ReadingError,
ParsingError,
impl Display for Error
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
match self
Error::ReadingError =>
f.write_str("Error while reading input line from standard input.")
Error::ParsingError =>
f.write_str("Input line does not meet format requirements: (a, b, c, ..., d)")
impl error::Error for Error
impl std::convert::From<std::io::Error> for Error
fn from(_e: std::io::Error) -> Self
Error::ReadingError
What are youre thoughts? What can I do better or in a more elegant way?
programming-challenge rust
add a comment |Â
up vote
6
down vote
favorite
I wrote the following Rust code to solve this task on /r/DailyProgrammer.
Given an n-tuple of numbers as input, the Ducci Sequence is formed by
taking the absolute difference of the difference between neighboring
elements. (The last result is the difference between the first and
last elements.)
Example input
[0; 653; 1854; 4063]
Example output
Emit the number of steps taken to get to either an all 0 tuple or when
it enters a stable repeating pattern.[0; 653; 1854; 4063]
[653; 1201; 2209; 4063]
[548; 1008; 1854; 3410]
[460; 846; 1556; 2862]
[386; 710; 1306; 2402]
[324; 596; 1096; 2016]
[272; 500; 920; 1692]
[228; 420; 772; 1420]
[192; 352; 648; 1192]
[160; 296; 544; 1000]
[136; 248; 456; 840]
[112; 208; 384; 704]
[96; 176; 320; 592]
[80; 144; 272; 496]
[64; 128; 224; 416]
[64; 96; 192; 352]
[32; 96; 160; 288]
[64; 64; 128; 256]
[0; 64; 128; 192]
[64; 64; 64; 192]
[0; 0; 128; 128]
[0; 128; 0; 128]
[128; 128; 128; 128]
[0; 0; 0; 0]
24 steps
I'm aware all the extra functions and error handling are a bit exaggerated for a task this easy, but I'm learning rust at the moment so I tried to get things right.
extern crate regex;
use std::io::Write;
use std::fmt::Display;
use std::fmt;
use regex::Regex;
use std::io;
use std::error;
fn main()
match read_input()
Ok(tuple) =>
run(tuple);
Err(e) =>
eprintln!("An error occured: ", e);
/// Tries to read input from standard input
fn read_input() -> Result<Tuple, Error>
print!("input: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Tuple::new(input)
/// runs Ducci sequence calculation and prints every step
fn run(tuple: Tuple)
let mut i = tuple;
let mut history: Vec<Tuple> = Vec::new();
let mut steps = 1;
while !&i.zeros() && !history.contains(&i)
let next = i.next();
history.push(i);
i = next;
println!("", i);
steps += 1;
println!(" steps", steps);
struct Tuple
data: Vec<i32>,
impl Tuple
fn new(line: String) -> Result<Tuple, Error>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line.as_str())
Err(Error::ParsingError)
else
// seperate single numbers, parse to integer and push into tuple instance
let sep = Regex::new(r"(,
/// Calculates and returns next tuple in ducci sequence
fn next(&self) -> Tuple
let mut data: Vec<i32> = Vec::new();
// calculate first n - 1 new values
for i in 0..self.dimension() - 1
data.push((self.data[i] - self.data[i + 1]).abs());
// calculate last value
data.push((self.data[self.dimension() - 1] - self.data[0]).abs());
Tuple
data: data,
/// Returns tuples dimension
fn dimension(&self) -> usize
self.data.len()
/// Determines whether tuple only contains zeros
fn zeros(&self) -> bool
self.data.iter().fold(true,
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
let mut e = true;
for i in 0..self.dimension()
e = e && self.data[i] == other.data[i];
e
impl Display for Tuple
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
let mut s = String::new();
s.push_str("[");
for i in 0..self.dimension() - 1
s.push_str(self.data[i].to_string().as_str());
s.push_str("; ");
s.push_str(self.data[self.dimension() - 1].to_string().as_str());
s.push_str("]");
write!(f, "", s)
#[derive(Debug)]
enum Error
ReadingError,
ParsingError,
impl Display for Error
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
match self
Error::ReadingError =>
f.write_str("Error while reading input line from standard input.")
Error::ParsingError =>
f.write_str("Input line does not meet format requirements: (a, b, c, ..., d)")
impl error::Error for Error
impl std::convert::From<std::io::Error> for Error
fn from(_e: std::io::Error) -> Self
Error::ReadingError
What are youre thoughts? What can I do better or in a more elegant way?
programming-challenge rust
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
I wrote the following Rust code to solve this task on /r/DailyProgrammer.
Given an n-tuple of numbers as input, the Ducci Sequence is formed by
taking the absolute difference of the difference between neighboring
elements. (The last result is the difference between the first and
last elements.)
Example input
[0; 653; 1854; 4063]
Example output
Emit the number of steps taken to get to either an all 0 tuple or when
it enters a stable repeating pattern.[0; 653; 1854; 4063]
[653; 1201; 2209; 4063]
[548; 1008; 1854; 3410]
[460; 846; 1556; 2862]
[386; 710; 1306; 2402]
[324; 596; 1096; 2016]
[272; 500; 920; 1692]
[228; 420; 772; 1420]
[192; 352; 648; 1192]
[160; 296; 544; 1000]
[136; 248; 456; 840]
[112; 208; 384; 704]
[96; 176; 320; 592]
[80; 144; 272; 496]
[64; 128; 224; 416]
[64; 96; 192; 352]
[32; 96; 160; 288]
[64; 64; 128; 256]
[0; 64; 128; 192]
[64; 64; 64; 192]
[0; 0; 128; 128]
[0; 128; 0; 128]
[128; 128; 128; 128]
[0; 0; 0; 0]
24 steps
I'm aware all the extra functions and error handling are a bit exaggerated for a task this easy, but I'm learning rust at the moment so I tried to get things right.
extern crate regex;
use std::io::Write;
use std::fmt::Display;
use std::fmt;
use regex::Regex;
use std::io;
use std::error;
fn main()
match read_input()
Ok(tuple) =>
run(tuple);
Err(e) =>
eprintln!("An error occured: ", e);
/// Tries to read input from standard input
fn read_input() -> Result<Tuple, Error>
print!("input: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Tuple::new(input)
/// runs Ducci sequence calculation and prints every step
fn run(tuple: Tuple)
let mut i = tuple;
let mut history: Vec<Tuple> = Vec::new();
let mut steps = 1;
while !&i.zeros() && !history.contains(&i)
let next = i.next();
history.push(i);
i = next;
println!("", i);
steps += 1;
println!(" steps", steps);
struct Tuple
data: Vec<i32>,
impl Tuple
fn new(line: String) -> Result<Tuple, Error>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line.as_str())
Err(Error::ParsingError)
else
// seperate single numbers, parse to integer and push into tuple instance
let sep = Regex::new(r"(,
/// Calculates and returns next tuple in ducci sequence
fn next(&self) -> Tuple
let mut data: Vec<i32> = Vec::new();
// calculate first n - 1 new values
for i in 0..self.dimension() - 1
data.push((self.data[i] - self.data[i + 1]).abs());
// calculate last value
data.push((self.data[self.dimension() - 1] - self.data[0]).abs());
Tuple
data: data,
/// Returns tuples dimension
fn dimension(&self) -> usize
self.data.len()
/// Determines whether tuple only contains zeros
fn zeros(&self) -> bool
self.data.iter().fold(true,
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
let mut e = true;
for i in 0..self.dimension()
e = e && self.data[i] == other.data[i];
e
impl Display for Tuple
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
let mut s = String::new();
s.push_str("[");
for i in 0..self.dimension() - 1
s.push_str(self.data[i].to_string().as_str());
s.push_str("; ");
s.push_str(self.data[self.dimension() - 1].to_string().as_str());
s.push_str("]");
write!(f, "", s)
#[derive(Debug)]
enum Error
ReadingError,
ParsingError,
impl Display for Error
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
match self
Error::ReadingError =>
f.write_str("Error while reading input line from standard input.")
Error::ParsingError =>
f.write_str("Input line does not meet format requirements: (a, b, c, ..., d)")
impl error::Error for Error
impl std::convert::From<std::io::Error> for Error
fn from(_e: std::io::Error) -> Self
Error::ReadingError
What are youre thoughts? What can I do better or in a more elegant way?
programming-challenge rust
I wrote the following Rust code to solve this task on /r/DailyProgrammer.
Given an n-tuple of numbers as input, the Ducci Sequence is formed by
taking the absolute difference of the difference between neighboring
elements. (The last result is the difference between the first and
last elements.)
Example input
[0; 653; 1854; 4063]
Example output
Emit the number of steps taken to get to either an all 0 tuple or when
it enters a stable repeating pattern.[0; 653; 1854; 4063]
[653; 1201; 2209; 4063]
[548; 1008; 1854; 3410]
[460; 846; 1556; 2862]
[386; 710; 1306; 2402]
[324; 596; 1096; 2016]
[272; 500; 920; 1692]
[228; 420; 772; 1420]
[192; 352; 648; 1192]
[160; 296; 544; 1000]
[136; 248; 456; 840]
[112; 208; 384; 704]
[96; 176; 320; 592]
[80; 144; 272; 496]
[64; 128; 224; 416]
[64; 96; 192; 352]
[32; 96; 160; 288]
[64; 64; 128; 256]
[0; 64; 128; 192]
[64; 64; 64; 192]
[0; 0; 128; 128]
[0; 128; 0; 128]
[128; 128; 128; 128]
[0; 0; 0; 0]
24 steps
I'm aware all the extra functions and error handling are a bit exaggerated for a task this easy, but I'm learning rust at the moment so I tried to get things right.
extern crate regex;
use std::io::Write;
use std::fmt::Display;
use std::fmt;
use regex::Regex;
use std::io;
use std::error;
fn main()
match read_input()
Ok(tuple) =>
run(tuple);
Err(e) =>
eprintln!("An error occured: ", e);
/// Tries to read input from standard input
fn read_input() -> Result<Tuple, Error>
print!("input: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input)?;
Tuple::new(input)
/// runs Ducci sequence calculation and prints every step
fn run(tuple: Tuple)
let mut i = tuple;
let mut history: Vec<Tuple> = Vec::new();
let mut steps = 1;
while !&i.zeros() && !history.contains(&i)
let next = i.next();
history.push(i);
i = next;
println!("", i);
steps += 1;
println!(" steps", steps);
struct Tuple
data: Vec<i32>,
impl Tuple
fn new(line: String) -> Result<Tuple, Error>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line.as_str())
Err(Error::ParsingError)
else
// seperate single numbers, parse to integer and push into tuple instance
let sep = Regex::new(r"(,
/// Calculates and returns next tuple in ducci sequence
fn next(&self) -> Tuple
let mut data: Vec<i32> = Vec::new();
// calculate first n - 1 new values
for i in 0..self.dimension() - 1
data.push((self.data[i] - self.data[i + 1]).abs());
// calculate last value
data.push((self.data[self.dimension() - 1] - self.data[0]).abs());
Tuple
data: data,
/// Returns tuples dimension
fn dimension(&self) -> usize
self.data.len()
/// Determines whether tuple only contains zeros
fn zeros(&self) -> bool
self.data.iter().fold(true,
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
let mut e = true;
for i in 0..self.dimension()
e = e && self.data[i] == other.data[i];
e
impl Display for Tuple
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
let mut s = String::new();
s.push_str("[");
for i in 0..self.dimension() - 1
s.push_str(self.data[i].to_string().as_str());
s.push_str("; ");
s.push_str(self.data[self.dimension() - 1].to_string().as_str());
s.push_str("]");
write!(f, "", s)
#[derive(Debug)]
enum Error
ReadingError,
ParsingError,
impl Display for Error
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
match self
Error::ReadingError =>
f.write_str("Error while reading input line from standard input.")
Error::ParsingError =>
f.write_str("Input line does not meet format requirements: (a, b, c, ..., d)")
impl error::Error for Error
impl std::convert::From<std::io::Error> for Error
fn from(_e: std::io::Error) -> Self
Error::ReadingError
What are youre thoughts? What can I do better or in a more elegant way?
programming-challenge rust
edited Jul 16 at 13:23
200_success
123k14143399
123k14143399
asked Jul 16 at 11:18
PEAR
1686
1686
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
4
down vote
This is only a summary of some remarks that came to mind when I read your code. It looks good, but I would run it through rustfmt
. Also, your delimiters are parentheses and commas ((â¦,â¦)
) instead of brackets and semicolons ([â¦;â¦]
), that seems off.
Use return
to short-circuit were appropriate
While you can use expressions instead of explicit return
s, an explicit return
can make a function simpler in some circumstances. For example, your eq
implementation can get simplified:
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
for i in 0..self.dimension()
if self.data[i] != other.data[i]
return false;
true
We don't have any mutable state e
. Furthermore, if the first element differs, we don't need to check all elements.
Use derive
where appropriate
However, your PartialEq
implementation acts the same as the Vec<i32>
one. It's therefore appropriate to use
#[derive(PartialEq, Debug)]
struct Tuple
â¦
instead. No need to reinvent the wheel here.
Follow existing interfaces
Your fn new(input: String) -> Result<â¦,â¦>
looks almost like from_str
. We should use from_str
from FromStr
instead:
impl FromStr for Tuple
type Err = Error;
fn from_str(line: &str) -> Result<Self, Self::Err>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line)
Err(Error::ParsingError)
else ))").unwrap();
let mut data: Vec<i32> = Vec::new();
for numbers in sep.split(line)
match numbers.parse::<i32>()
Ok(number) =>
data.push(number);
,
// ignore newline and empty captures
Err(_) => ,
Ok(Tuple
data: data,
)
Prefer non-owning types when possible
As you can see, from_str
uses &str
instead of String
. from_str
doesn't need to take ownership of the string, and neither did your original new
. Indeed, all your uses of line
in new
needed as_str()
.
Use specialized functions where appropriate
zeroes
uses fold
with a boolean state. This has the same problem as your eq
implementation: if the first number differs from zero, we will still check all numbers.
Instead, use all
:
fn zeros(&self) -> bool x
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
About derives, thefn new(line: String) -> Result<Tuple, Error>
should be an implementation ofFromStr
â Boiethios
Jul 17 at 7:01
add a comment |Â
up vote
3
down vote
Not a review, but an extended comment.
The loop detection by means of history
drives the time complexity quadratic to the number of steps. There are two ways out: either
use a Floyd loop detection (with
slow
andfast
tuples), orexploit the property of Ducci sequence: it becomes periodic once it reaches the "binary" form, that is all non-zero elements are equal.
This way you don't need history
at all. Space complexity is $O(1)$, and time complexity is linear to the number of steps.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
This is only a summary of some remarks that came to mind when I read your code. It looks good, but I would run it through rustfmt
. Also, your delimiters are parentheses and commas ((â¦,â¦)
) instead of brackets and semicolons ([â¦;â¦]
), that seems off.
Use return
to short-circuit were appropriate
While you can use expressions instead of explicit return
s, an explicit return
can make a function simpler in some circumstances. For example, your eq
implementation can get simplified:
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
for i in 0..self.dimension()
if self.data[i] != other.data[i]
return false;
true
We don't have any mutable state e
. Furthermore, if the first element differs, we don't need to check all elements.
Use derive
where appropriate
However, your PartialEq
implementation acts the same as the Vec<i32>
one. It's therefore appropriate to use
#[derive(PartialEq, Debug)]
struct Tuple
â¦
instead. No need to reinvent the wheel here.
Follow existing interfaces
Your fn new(input: String) -> Result<â¦,â¦>
looks almost like from_str
. We should use from_str
from FromStr
instead:
impl FromStr for Tuple
type Err = Error;
fn from_str(line: &str) -> Result<Self, Self::Err>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line)
Err(Error::ParsingError)
else ))").unwrap();
let mut data: Vec<i32> = Vec::new();
for numbers in sep.split(line)
match numbers.parse::<i32>()
Ok(number) =>
data.push(number);
,
// ignore newline and empty captures
Err(_) => ,
Ok(Tuple
data: data,
)
Prefer non-owning types when possible
As you can see, from_str
uses &str
instead of String
. from_str
doesn't need to take ownership of the string, and neither did your original new
. Indeed, all your uses of line
in new
needed as_str()
.
Use specialized functions where appropriate
zeroes
uses fold
with a boolean state. This has the same problem as your eq
implementation: if the first number differs from zero, we will still check all numbers.
Instead, use all
:
fn zeros(&self) -> bool x
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
About derives, thefn new(line: String) -> Result<Tuple, Error>
should be an implementation ofFromStr
â Boiethios
Jul 17 at 7:01
add a comment |Â
up vote
4
down vote
This is only a summary of some remarks that came to mind when I read your code. It looks good, but I would run it through rustfmt
. Also, your delimiters are parentheses and commas ((â¦,â¦)
) instead of brackets and semicolons ([â¦;â¦]
), that seems off.
Use return
to short-circuit were appropriate
While you can use expressions instead of explicit return
s, an explicit return
can make a function simpler in some circumstances. For example, your eq
implementation can get simplified:
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
for i in 0..self.dimension()
if self.data[i] != other.data[i]
return false;
true
We don't have any mutable state e
. Furthermore, if the first element differs, we don't need to check all elements.
Use derive
where appropriate
However, your PartialEq
implementation acts the same as the Vec<i32>
one. It's therefore appropriate to use
#[derive(PartialEq, Debug)]
struct Tuple
â¦
instead. No need to reinvent the wheel here.
Follow existing interfaces
Your fn new(input: String) -> Result<â¦,â¦>
looks almost like from_str
. We should use from_str
from FromStr
instead:
impl FromStr for Tuple
type Err = Error;
fn from_str(line: &str) -> Result<Self, Self::Err>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line)
Err(Error::ParsingError)
else ))").unwrap();
let mut data: Vec<i32> = Vec::new();
for numbers in sep.split(line)
match numbers.parse::<i32>()
Ok(number) =>
data.push(number);
,
// ignore newline and empty captures
Err(_) => ,
Ok(Tuple
data: data,
)
Prefer non-owning types when possible
As you can see, from_str
uses &str
instead of String
. from_str
doesn't need to take ownership of the string, and neither did your original new
. Indeed, all your uses of line
in new
needed as_str()
.
Use specialized functions where appropriate
zeroes
uses fold
with a boolean state. This has the same problem as your eq
implementation: if the first number differs from zero, we will still check all numbers.
Instead, use all
:
fn zeros(&self) -> bool x
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
About derives, thefn new(line: String) -> Result<Tuple, Error>
should be an implementation ofFromStr
â Boiethios
Jul 17 at 7:01
add a comment |Â
up vote
4
down vote
up vote
4
down vote
This is only a summary of some remarks that came to mind when I read your code. It looks good, but I would run it through rustfmt
. Also, your delimiters are parentheses and commas ((â¦,â¦)
) instead of brackets and semicolons ([â¦;â¦]
), that seems off.
Use return
to short-circuit were appropriate
While you can use expressions instead of explicit return
s, an explicit return
can make a function simpler in some circumstances. For example, your eq
implementation can get simplified:
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
for i in 0..self.dimension()
if self.data[i] != other.data[i]
return false;
true
We don't have any mutable state e
. Furthermore, if the first element differs, we don't need to check all elements.
Use derive
where appropriate
However, your PartialEq
implementation acts the same as the Vec<i32>
one. It's therefore appropriate to use
#[derive(PartialEq, Debug)]
struct Tuple
â¦
instead. No need to reinvent the wheel here.
Follow existing interfaces
Your fn new(input: String) -> Result<â¦,â¦>
looks almost like from_str
. We should use from_str
from FromStr
instead:
impl FromStr for Tuple
type Err = Error;
fn from_str(line: &str) -> Result<Self, Self::Err>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line)
Err(Error::ParsingError)
else ))").unwrap();
let mut data: Vec<i32> = Vec::new();
for numbers in sep.split(line)
match numbers.parse::<i32>()
Ok(number) =>
data.push(number);
,
// ignore newline and empty captures
Err(_) => ,
Ok(Tuple
data: data,
)
Prefer non-owning types when possible
As you can see, from_str
uses &str
instead of String
. from_str
doesn't need to take ownership of the string, and neither did your original new
. Indeed, all your uses of line
in new
needed as_str()
.
Use specialized functions where appropriate
zeroes
uses fold
with a boolean state. This has the same problem as your eq
implementation: if the first number differs from zero, we will still check all numbers.
Instead, use all
:
fn zeros(&self) -> bool x
This is only a summary of some remarks that came to mind when I read your code. It looks good, but I would run it through rustfmt
. Also, your delimiters are parentheses and commas ((â¦,â¦)
) instead of brackets and semicolons ([â¦;â¦]
), that seems off.
Use return
to short-circuit were appropriate
While you can use expressions instead of explicit return
s, an explicit return
can make a function simpler in some circumstances. For example, your eq
implementation can get simplified:
impl PartialEq for Tuple
fn eq(&self, other: &Tuple) -> bool
if self.dimension() != other.dimension()
false
else
for i in 0..self.dimension()
if self.data[i] != other.data[i]
return false;
true
We don't have any mutable state e
. Furthermore, if the first element differs, we don't need to check all elements.
Use derive
where appropriate
However, your PartialEq
implementation acts the same as the Vec<i32>
one. It's therefore appropriate to use
#[derive(PartialEq, Debug)]
struct Tuple
â¦
instead. No need to reinvent the wheel here.
Follow existing interfaces
Your fn new(input: String) -> Result<â¦,â¦>
looks almost like from_str
. We should use from_str
from FromStr
instead:
impl FromStr for Tuple
type Err = Error;
fn from_str(line: &str) -> Result<Self, Self::Err>
// Regex for allowed inputs: (a, b, c, ..., d)
let re = Regex::new(r"(((d)+, )*(d)+)").unwrap();
if!re.is_match(line)
Err(Error::ParsingError)
else ))").unwrap();
let mut data: Vec<i32> = Vec::new();
for numbers in sep.split(line)
match numbers.parse::<i32>()
Ok(number) =>
data.push(number);
,
// ignore newline and empty captures
Err(_) => ,
Ok(Tuple
data: data,
)
Prefer non-owning types when possible
As you can see, from_str
uses &str
instead of String
. from_str
doesn't need to take ownership of the string, and neither did your original new
. Indeed, all your uses of line
in new
needed as_str()
.
Use specialized functions where appropriate
zeroes
uses fold
with a boolean state. This has the same problem as your eq
implementation: if the first number differs from zero, we will still check all numbers.
Instead, use all
:
fn zeros(&self) -> bool x
edited Jul 17 at 7:28
answered Jul 16 at 14:42
Zeta
14.3k23267
14.3k23267
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
About derives, thefn new(line: String) -> Result<Tuple, Error>
should be an implementation ofFromStr
â Boiethios
Jul 17 at 7:01
add a comment |Â
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
About derives, thefn new(line: String) -> Result<Tuple, Error>
should be an implementation ofFromStr
â Boiethios
Jul 17 at 7:01
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
Thank you for your comments. Regarding my delimiters I wasn't sure what to use, because both versions are present in the task.
â PEAR
Jul 16 at 15:06
1
1
About derives, the
fn new(line: String) -> Result<Tuple, Error>
should be an implementation of FromStr
â Boiethios
Jul 17 at 7:01
About derives, the
fn new(line: String) -> Result<Tuple, Error>
should be an implementation of FromStr
â Boiethios
Jul 17 at 7:01
add a comment |Â
up vote
3
down vote
Not a review, but an extended comment.
The loop detection by means of history
drives the time complexity quadratic to the number of steps. There are two ways out: either
use a Floyd loop detection (with
slow
andfast
tuples), orexploit the property of Ducci sequence: it becomes periodic once it reaches the "binary" form, that is all non-zero elements are equal.
This way you don't need history
at all. Space complexity is $O(1)$, and time complexity is linear to the number of steps.
add a comment |Â
up vote
3
down vote
Not a review, but an extended comment.
The loop detection by means of history
drives the time complexity quadratic to the number of steps. There are two ways out: either
use a Floyd loop detection (with
slow
andfast
tuples), orexploit the property of Ducci sequence: it becomes periodic once it reaches the "binary" form, that is all non-zero elements are equal.
This way you don't need history
at all. Space complexity is $O(1)$, and time complexity is linear to the number of steps.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Not a review, but an extended comment.
The loop detection by means of history
drives the time complexity quadratic to the number of steps. There are two ways out: either
use a Floyd loop detection (with
slow
andfast
tuples), orexploit the property of Ducci sequence: it becomes periodic once it reaches the "binary" form, that is all non-zero elements are equal.
This way you don't need history
at all. Space complexity is $O(1)$, and time complexity is linear to the number of steps.
Not a review, but an extended comment.
The loop detection by means of history
drives the time complexity quadratic to the number of steps. There are two ways out: either
use a Floyd loop detection (with
slow
andfast
tuples), orexploit the property of Ducci sequence: it becomes periodic once it reaches the "binary" form, that is all non-zero elements are equal.
This way you don't need history
at all. Space complexity is $O(1)$, and time complexity is linear to the number of steps.
answered Jul 16 at 17:01
vnp
36.3k12890
36.3k12890
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f199585%2fthe-ducci-sequence%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password