Skip to content
Merged
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
66 changes: 66 additions & 0 deletions src/bin/43_iterators_indepth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,72 @@ fn main() -> std::io::Result<()> {
println!("Max = {max}, Min = {min}");

// max_by and min_by
// any, all: applies a closure to an iterator and returns true is any/all the element return true for the closure

// building collections with the collect method
// When any type implements the FromIterator<T> trait, a collection of that type can be derived from an iterator
// with the collect method
//

#[allow(unused_doc_comments)]
/**
*
* trait FromIterator<A>: Sized {
* fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> Self;
* }
*/
#[allow(clippy::useless_vec)]
let numbers = vec![1, 2, 3, 4, 5, 6];
let names = vec!["Brian".to_string(), "Obot".to_string(), "David".to_string()];
let _numbers_iter = numbers.iter();
let names_iter = names.iter();

let _collection = names_iter.collect::<Vec<&String>>();
println!("Names: {names:?}");

// Extend traits allow types to add Iterable items to itself
let mut cars = vec!["Benz", "Toyota", "Nissan"];
cars.extend(&["Jeep", "Tesla", "Honda"]);
println!("Cars: {cars:?}");

// All standard collection implement the Extend trait and so they have the extend method, so does String
// Array and slices which have fixed length do not

// partition method divivdes an iterator items among two collection, using a closure to decide where each item belongs
let things = ["doorknob", "mushroom", "noddle", "giraffe", "grapefruit"];
let (living, nonliving): (Vec<&str>, Vec<&str>) = things
.iter()
.partition(|thing| thing.as_bytes()[0] & 1 != 0);

println!("Living Things: {living:?}");
println!("None Living Things: {nonliving:?}");

// like collect, partition makes any type of collection you specify in the type annotation

struct F32Range {
start: f32,
end: f32,
}

impl Iterator for F32Range {
type Item = f32;

fn next(&mut self) -> Option<Self::Item> {
if self.start >= self.end {
return None;
}
let result = Some(self.start);
self.start += 0.1;
result
}
}

for i in (F32Range {
start: 1.0,
end: 10.0,
}) {
println!("I: {i}");
}

Ok(())
}
88 changes: 88 additions & 0 deletions src/bin/44_collections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
fn main() {
// Common collection types in Rust
// Vec<T>: Growable array
// VecDeque<T>: Double Ended Queue
// LinkedList<T>: Doubly Linked List
// BinaryHeap<T>: Max Heap
// HashMap<K, V>: key-value hash table
// BTreeMap<K, V>: sorted key-value table
// HashSet<T>: unoredered hash based set
// BTreeSet<T>: sorted set

// empty vector
#[allow(unused_mut, unused_variables)]
let mut numbers: Vec<i32> = vec![];

// vector with some content
#[allow(clippy::useless_vec)]
let words = vec!["Niche", "Opulence", "Insouciant"];
let sub_word = words[0..2].to_vec();

println!("Sub word: {sub_word:?}");

fn first_word(s: &String) -> usize {
let bytes = s.as_bytes();
println!("Bytes Form: {bytes:?}");

for (i, &item) in bytes.iter().enumerate() {
println!("Bytes [{i}]: {item}");
}

s.len()
}

let first_name_end_index = first_word(&"Brian David Obot".to_string());
println!(
"First Name = {}",
&"Brian David Obot"[0..first_name_end_index]
);

// methods available on slices
#[allow(clippy::useless_vec)]
let names = vec![1, 2, 3, 4, 5, 6];
let _first = &names[..].first(); // returns a reference to the first item of a slice as an Option
let _last = &names[..].last(); // returns a reference to the last item of a slice as an Option
let _item = &names[..].get(10); // get the item at the index, if the item exist or None

// each of the methods above have a mut variant that returns a mutable reference to the items
// .to_vec(): Makes copies of the slice creating a new vector from the item in it, this is only available if the elements are cloneable
//
// .len(): returns the length of the slice
// .is_empty(): returns True if the slice contains no element
//
// Vector specific methods
// .capacity(): returns the capacity of a vector
// .reserve(n): reserves enough space for n more items in the vectors capacity
// .reserve_exact(n): reserves exactly enough space for n item and no more
// .shrink_to_fit(): tries to free up extra space is capaccity > length
// .push(value): Add an element to the vector
// .pop(): removes nd return the last element from a vector as an Option
// .insert(index, value)
// .remove(index)
// .resize(new_size, new_value): increase the length of a vector to new_size and fills extra spaces with new_value as needed
// .resize_with(new_len, closure): same as above, but uses a closure to generate the new_values
// .truncate(new_len): cut a vector to a length dropping all elements outide this length
// .clear(): same as truncate(0)
// .extend(iterable): takes a value that implements IntoIterator and extends the vector with the values from it
// .split_off(index): like truncate, but the dropped values are returns as a vector to the caller similar to pop but for many values
// .append(vec2): Moves all elements from vec2 into the vector leving vec2 empty afterwards
// .drain(range)
// .retain(test): drops all elements that don't pass the test provided in the function, similar to calling filter and then collect on a iterator
// .dedup(): drops duplicate adjacent values so that only one is left
// .reverse(): reverse a slice in place
// Once a slice is sorted it can be efficiently searched
// .binary_search(&value)
// .binary_search_by(&value, cmp)
//
//
// These methods work on arrays of arrays
// .concat(): return a new vector by concatenating all the slices
// .join(&seperator): same as above, except that the seperator is inserted between slices
//
// to get the index of an item in a slice use the position method on the iterator
// slice.iter().postion(|x| *x == value)

// Random elements
// .choose(&mut rng)
// .shuffle(&mut rng)
}