I am currently working on a project, in which I am referencing a grid quite often. This grid uses both X and Y axis. When I want to iterate through the grid I use two nested for loops, one for each axis.
for x in range 0..10
{
for y in range 0..20
{
}
}
I was wondering if there was any way to make this more neat / easier to read by using only one line of code. To look more like...
for x in range 0..10 && y in range 0..20
{
}
This would generally help the readability. This obviously assumes there would be no code in just the x loop.
As others pointed out, .flat_map() is the way to go to avoid writting nested expressions in a classical way, and without adding external deps to your project.
fn main() {
for (i, j) in (0..10).flat_map(|i| (0..20).map(move |j| (i, j))) {
// do job here
}
}
Related
I have a slice of unknown length and I would like to try get a slice to the last N elements of that slice. The only way I can think of doing this is as follows (e.g., for 4 elements):
if let [.., a, b, c, d] = my_slice {
//...
}
This feels very cumbersome though. I would have thought that one of the range expressions would have provided this functionality, but none of them seem to do so... Is there another way of doing this? Ideally, I would be able to work with a slice and not the individual values a, b, c, d in my example above.
I like your solution, but you could use get. A simple version looks like this:
fn last4<T>(slc: &[T]) -> Option<&[T]> {
slc.get(slc.len()-4..slc.len())
}
In practice, you'd need to check that slc.len() is at least 4.
See it in action: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2c9472aea45cf23b1f46b54de7132cd7.
Say I have a hash map m: HashMap<K, V>, a key k: K and a value v: V, and would like to do the following:
If m does not contain a value at index k, insert v at index k.
If m contains a value w at index k, apply a function fn combine(x: V, y: V) -> Option<V> to v and w, and:
If the result is None, remove the entry at index k from m.
If the result is Some(u), replace the value at index k by u.
Is there a way to do this "in-place", without calling functions that access, modify or remove the value at k multiple times?
I would also like to avoid copying data, so ideally one shouldn't need to clone v to feed the clones into insert and combine separately.
I could rewrite combine to use (mutable) references (or inline it), but the wish of not copying data still remains.
Digging deeper into the Entry documentation, I noticed that the variants of the Entry enum offer functions to modify, remove or insert entries in-place.
After taking std::collections::hash_map::Entry into scope, one could do the following:
match m.entry(k) {
Entry::Occupied(mut oe) => {
let w = oe.get_mut();
match combine(v, w) {
Some(u) => { *w = u; },
None => { oe.remove_entry(); },
}
},
Entry::Vacant(ve) => { ve.insert(v); },
}
(Here is a PoC in the Rust playground.)
This, however, requires combine to take a (mutable) reference as its second argument (which is fine in my case).
I managed to do it in one access, one write and one key-deletion in total in the worst case. The last key-deletion should not be necessary, but I'm not certain it can be done. I gave it my best so far. I hope this helps!
Okay, so I think we want to use the Entry API.
The full method list for Entry is here.
I think we'd do it in the following order:
If m contains a value w at index k: (two more steps)
Or insert v at index k.
This can be done by using .and_modify and then .or_insert. Something like this:
let map = // ... Initialize the map
// Do stuff to it
// ...
// Our important bit:
let mut delete_entry = false;
map.entry(k)
.and_modify(|w| { // If the entry exists, we modify it
let u = combine(v, w);
match u {
Some(y) => *w = y;
None => delete_entry = true;
}
}
)
.or_insert(v); // If it doesn't, we insert v
if delete_entry {
map.remove(k);
}
I don't think there's a way to do all three things without that last map.remove access, so this is my best attempt for now.
This appears to be covered by the Str module in the api documentation but according to this issue opened this is an oversight.
This is perhaps the simplest, though certainly not the most efficient:
let split = s =>
s |> Js.String.split("")
|> Array.to_list
|> List.map(s => s.[0])
This is more efficient, and cross-platform:
let split = s => {
let rec aux = (acc, i) =>
if (i >= 0) {
aux([s.[i], ...acc], i - 1)
} else {
acc
}
aux([], String.length(s) - 1)
}
I don't think it usually makes much sense to convert a string to a list though, since the conversion will have significant overhead regardless of method and it'd be better to just iterate the string directly. If it does make sense it's probably when the strings are small enough that the difference between the first and second method matters little.
"When you've found the treasure, stop digging!"
I'm wanting to use more functional programming in Groovy, and thought rewriting the following method would be good training. It's harder than it looks because Groovy doesn't appear to build short-circuiting into its more functional features.
Here's an imperative function to do the job:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
String shortestUniqueName(String nameToShorten) {
def currentLevel = 1
String shortName = ''
def separator = '/'
while (fullyQualifiedNames.findAll { fqName ->
shortName = nameToShorten.tokenize(separator)[-currentLevel..-1].join(separator)
fqName.endsWith(shortName)
}.size() > 1) {
++currentLevel
}
return shortName
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
It scans a list of fully-qualified filenames and returns the shortest unique form. There are potentially hundreds of fully-qualified names.
As soon as the method finds a short name with only one match, that short name is the right answer, and the iteration can stop. There's no need to scan the rest of the name or do any more expensive list searches.
But turning to a more functional flow in Groovy, neither return nor break can drop you out of the iteration:
return simply returns from the present iteration, not from the whole .each so it doesn't short-circuit.
break isn't allowed outside of a loop, and .each {} and .eachWithIndex {} are not considered loop constructs.
I can't use .find() instead of .findAll() because my program logic requires that I scan all elements of the list, nut just stop at the first.
There are plenty of reasons not to use try..catch blocks, but the best I've read is from here:
Exceptions are basically non-local goto statements with all the
consequences of the latter. Using exceptions for flow control
violates the principle of least astonishment, make programs hard to read
(remember that programs are written for programmers first).
Some of the usual ways around this problem are detailed here including a solution based on a new flavour of .each. This is the closest to a solution I've found so far, but I need to use .eachWithIndex() for my use case (in progress.)
Here's my own poor attempt at a short-circuiting functional solution:
fullyQualifiedNames = ['a/b/c/d/e', 'f/g/h/i/j', 'f/g/h/d/e']
def shortestUniqueName(String nameToShorten) {
def found = ''
def final separator = '/'
def nameComponents = nameToShorten.tokenize(separator).reverse()
nameComponents.eachWithIndex { String _, int i ->
if (!found) {
def candidate = nameComponents[0..i].reverse().join(separator)
def matches = fullyQualifiedNames.findAll { String fqName ->
fqName.endsWith candidate
}
if (matches.size() == 1) {
found = candidate
}
}
}
return found
}
println shortestUniqueName('a/b/c/d/e')
Result: c/d/e
Please shoot me down if there is a more idiomatic way to short-circuit in Groovy that I haven't thought of. Thank you!
There's probably a cleaner looking (and easier to read) solution, but you can do this sort of thing:
String shortestUniqueName(String nameToShorten) {
// Split the name to shorten, and make a list of all sequential combinations of elements
nameToShorten.split('/').reverse().inject([]) { agg, l ->
if(agg) agg + [agg[-1] + l] else agg << [l]
}
// Starting with the smallest element
.find { elements ->
fullyQualifiedNames.findAll { name ->
name.endsWith(elements.reverse().join('/'))
}.size() == 1
}
?.reverse()
?.join('/')
?: ''
}
Is there an easy way to apply a step during iteration? I have seen a reference to step_by() in the book but I cant seem to get it to work.
For example, to print every-other character of a string I can do this but is there an easier way?
let s1 = "whhaatt".to_string();
for letter in s1.chars().enumerate() {
let (i, l) = letter;
if i % 2 == 0 {
println!("{:?}", l );
}
}
The simplest way would be to use the step adaptor from the itertools crate. In this case, you could use s1.chars().step(2).
Aside: Your code does not iterate over "characters"; it iterates over code points. It's quite likely that you want the graphemes method from the unicode-segmentation crate.