This question already has an answer here:
Is it possible to use a HashSet as the key to a HashMap?
(1 answer)
Closed 2 years ago.
I'm working through some problems on leetcode to get better at using Rust during interviews. As a first attempt to solve this problem, I thought of representing triplet solutions a + b + c = 0 by storing a, b, and c in a solution: HashSet<i32>, then storing that solution: HashSet<i32> in another collection solution_set: HashSet<HashSet<i32>>. Crazy, right?
The exercise explicitly states that redundant triplets don't qualify, so rather than storing the triplets in solution: Vec<i32>s where order might change a Vec's hash value, I thought I'd store the triplets in solution: HashSet<i32> so any ordering of a, b, and c resolves to the same solution. Additionally, it would be O(1) time to verify that a triplet already exists in solution_set: HashSet<HashSet<i32>>, rather than O(n) to check if it exists in the alternative solution_set: Vec<HashSet<i32>>. Finally, I know the return value is Vec<Vec<i32>>, but that's solved by drain()ing the solution: HashSet<i32> into Vec<i32>, and then draining the resulting Iter<Vec<i32>> into a Vec<Vec<i32>>.
I recognize that HashSet<T> does not implement Hash, so I decided to try to myself, and now I'm up a paddle without a creek. 🚣 I looked here to learn about implementing Hash for a struct, and here to learn how to implement a trait on a struct I don't own, but now I'm re-implementing all the functions handles I need from HashSet (new(), drain(), insert(), etc) on HashSetWrapper. The compiler is also compaining about other traits too like PartialEq, so I've really opened pandora's box on this one. I just feel like this isn't the most "Rusty" way to do this.
Also, I know that implementing hashes correctly is not trivial, and as this is an effort in best practices I'd like some help figuring out the most "Rusty" way to implement my solution is. I haven't actually gotten it to work yet, but here's the code I have so far:
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
#[derive(PartialEq)]
struct HashSetWrapper<T>(HashSet<T>);
impl<T: Hash> HashSetWrapper<T> {
fn new() -> Self {
HashSetWrapper(HashSet::<T>::new())
}
fn insert(&self, value: T) {
self.0.insert(value);
}
}
impl<T: Hash> Hash for HashSetWrapper<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
for value in &self.0 {
value.hash(state);
}
}
}
impl Solution {
pub fn three_sum(nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut solution_set: HashSetWrapper<HashSet<i32>> = HashSetWrapper::new();
for (i, a) in nums[0..(nums.len() - 2)].iter().enumerate() {
for (j, b) in nums[i..(nums.len() - 1)].iter().enumerate() {
for c in nums[j..].iter() {
if a + b + c == 0 {
let mut temp = HashSet::<i32>::new();
temp.insert(*a);
temp.insert(*b);
temp.insert(*c);
solution_set.insert(temp); }
}
}
}
solution_set.drain().map(|inner_set| inner_set.drain().collect::<Vec<_>>()).collect::<Vec<_>>()
}
}
I still need to implement a drain() for my wrapper class, but I'm not even sure I'm going in the right direction. How would you solve this problem? How would you implement Hash on HashSet? I'd love to know!
Below are the errors the compiler is giving me:
Line 5, Char 26: binary operation `==` cannot be applied to type `std::collections::HashSet<T>` (solution.rs)
|
5 | struct HashSetWrapper<T>(HashSet<T>);
| ^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `std::collections::HashSet<T>`
Line 5, Char 26: binary operation `!=` cannot be applied to type `std::collections::HashSet<T>` (solution.rs)
|
5 | struct HashSetWrapper<T>(HashSet<T>);
| ^^^^^^^^^^
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `std::collections::HashSet<T>`
Line 9, Char 38: no function or associated item named `new` found for type `std::collections::HashSet<T>` in the current scope (solution.rs)
|
9 | HashSetWrapper(HashSet::<T>::new())
| ^^^ function or associated item not found in `std::collections::HashSet<T>`
|
= note: the method `new` exists but the following trait bounds were not satisfied:
`T : std::cmp::Eq`
Line 13, Char 16: no method named `insert` found for type `std::collections::HashSet<T>` in the current scope (solution.rs)
|
13 | self.0.insert(value);
| ^^^^^^ method not found in `std::collections::HashSet<T>`
|
= note: the method `insert` exists but the following trait bounds were not satisfied:
`T : std::cmp::Eq`
Line 28, Char 62: the trait bound `std::collections::HashSet<i32>: std::hash::Hash` is not satisfied (solution.rs)
|
8 | fn new() -> Self {
| ---------------- required by `HashSetWrapper::<T>::new`
...
28 | let mut solution_set: HashSetWrapper<HashSet<i32>> = HashSetWrapper::new();
| ^^^^^^^^^^^^^^^^^^^ the trait `std::hash::Hash` is not implemented for `std::collections::HashSet<i32>`
Line 38, Char 38: no method named `insert` found for type `HashSetWrapper<std::collections::HashSet<i32>>` in the current scope (solution.rs)
|
5 | struct HashSetWrapper<T>(HashSet<T>);
| ------------------------------------- method `insert` not found for this
...
38 | solution_set.insert(temp); }
| ^^^^^^ method not found in `HashSetWrapper<std::collections::HashSet<i32>>`
|
= note: the method `insert` exists but the following trait bounds were not satisfied:
`std::collections::HashSet<i32> : std::hash::Hash`
Line 42, Char 22: no method named `drain` found for type `HashSetWrapper<std::collections::HashSet<i32>>` in the current scope (solution.rs)
|
5 | struct HashSetWrapper<T>(HashSet<T>);
| ------------------------------------- method `drain` not found for this
...
42 | solution_set.drain().map(|inner_set| inner_set.drain().collect::<Vec<_>>()).collect::<Vec<_>>()
| ^^^^^ method not found in `HashSetWrapper<std::collections::HashSet<i32>>`
error: aborting due to 7 previous errors
I've just gone through your code and people's comments. I think that you're overly complicated yourself with the HashSet<i32>, and then having to implement all of the trait function for your HashSetWrapper. A simpler version is just to have a simple struct to keep your triplet, and let it derives from Hash, Eq and PartialEq using macro. To make the de-dup work automagically, we can sort the triplet as an earlier comment.
Following is my code that still roughly follow the logic of your three_sum implementation (it has a bug, btw), with this suggestion.
#[derive(Hash, Eq, PartialEq, Debug)]
pub struct Triplet {
x: i32,
y: i32,
z: i32,
}
impl Triplet {
pub fn new(x: i32, y: i32, z: i32) -> Triplet {
let mut v = vec![x, y, z];
v.sort();
Triplet {
x: v[0],
y: v[1],
z: v[2],
}
}
pub fn to_vec(&self) -> Vec<i32> {
vec![self.x, self.y, self.z]
}
}
pub fn three_sum(nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut res: HashSet<Triplet> = HashSet::new();
for (i, a) in nums[0..(nums.len() - 2)].iter().enumerate() {
for (j, b) in nums[i+1..(nums.len() - 1)].iter().enumerate() {
for c in nums[j+1..].iter() {
if a + b + c == 0 {
let triplet = Triplet::new(*a, *b, *c);
res.insert(triplet);
}
}
}
}
res.into_iter().map(|t| t.to_vec()).collect()
}
Test code:
#[test]
fn test_three_sum() {
let result = vec![vec![-1, -1, 2], vec![-1, 0, 1]];
assert_eq!(three_sum(vec![-1, 0, 1, 2, -1, -4]), result)
}
Result:
running 1 test
test tests::test_three_sum ... ok
Related
I need a macro that will call functions with different numbers of arguments or a macro that will generate a valid argument list from its (repeating) parameters.
I am fine with explicitly giving the information about the number of arguments to the macro, but I can't figure out how to generate the argument list for the function - I always stumble on the macros returning expressions rather than token tree.
I made the following playground example:
macro_rules! call (
($f: expr, $($params:tt)*) => {
$f(make_params!($($params:tt)*))
};
);
macro_rules! make_params {
() => {};
(I $($params: tt)*) => {
1, make_params!($($params:tt)*)
};
}
fn foo(a: i32, b: i32, c: i32) {
println!("foo: {} {} {}", a, b, c);
}
fn bar(a: i32, b: i32) {
println!("bar: {} {}", a, b);
}
fn main() {
call!(foo, I I I);
call!(bar, I I);
}
The compiler complains with the following:
error: macro expansion ignores token `,` and any following
--> src/main.rs:10:10
|
10 | 1, make_params!($($params:tt)*)
| ^
|
note: caused by the macro expansion here; the usage of `make_params!` is likely invalid in expression context
--> src/main.rs:3:12
|
3 | $f(make_params!($($params:tt)*))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
How can I treat the return of make_params! as a token stream (or such) rather than expression?
My real use case is a bit more involved than this toy example. My functions have multiple parameter types which are constructed in different ways. In my case, just making macros call1, call2!, ... does not seem like a good solution, as I would need the likes of call_IIOOI, call_IIIO, etc.
You need to build the function call progressively as you go and only emit it at once in the end:
macro_rules! call (
($f: expr, $($params:tt)*) => {
make_call!($f, () $($params)*)
};
);
macro_rules! make_call {
($f: expr, ($($args:tt)*)) => { $f($($args)*) };
($f: expr, () I $($params:tt)*) => {
make_call!($f, (1) $($params)*)
};
($f: expr, ($($args:tt)*) I $($params:tt)*) => {
make_call!($f, ($($args)*, 1) $($params)*)
};
}
playground
I've been shown a weird snippet in Scala which I don't quite understand. To me, assignments in Scala return Unit, unlike in Java where it returns the type of the variable which has been affected a value. However, let's consider this class :
case class C(i: Int) {
def f = C(i = i + 10)
}
This compiles completely fine, which is pretty weird ! The factory method C.apply expects an Int, whereas I pass it what seems to be an assignment, of type Unit. By the way if I remove the assignment to just let the expression, it seems to have the exact same behaviour.
Let's try this now :
case class C(i: Int) {
def f = {
i = i + 10
C(i = i + 10)
}
}
Ok now this is the world I know : i is a val, then you cannot mutate it so i = i + 10 does not compile. However, C(i = i + 10) still compiles without complaining. What is this weirdness ? Is there a reason for thatto exist ?
This is because, in the case of C(i = i + 10) the left-hand i is not the field C#i but a named parameter. No assignment is being done at all.
C(i = i + 10)
^ ^
+---|-------- Parameter name
|
+- - - - - - - - - - - - - - Reference to the field `i`
in the instance of the class `C`
Some places where named parameters make sense:
Avoiding the "what does this {boolean, integer} mean" moment:
someMethod(anObject, flagName=true)
// As opposed to someMethod(anObject, true) ... what's `true` for?
anotherMethod(arg1, arg2, totalMagic=33)
When using default values for parameters (to invoke the right constructor):
def withDefaults(i: Int, flag: Boolean = true, wrapper: Option[String] = None) = {
wrapper.fold(s"$i with $flag")(_.format(i, flag))
}
withDefaults(3, Some("stuff %s around %s"))
// won't compile
// error: type mismatch;
// found : Some[String]
// required: Boolean
withDefaults(3, wrapper = Some("stuff %s around %s"))
// works (returns "stuff 3 around true")
I have defined method double.
def double(i: Int): Int = i * 2
val p = double {
print("Hello!");
5
}
print(p)
As you can see we can pass not just integer argument, but we also can invoke some logic (print). Why can I do that? And how Scala do resolve it? What does really mean {} in Scala?
Your code is equivalent to:
val p = double({ //`{}` still means a block of code
print("Hello!")
5
})
or even:
def block = { //might be `def block() { ... }`
print("Hello!")
5
}
val p = double(block) //calling the block here, it's equivalent to double(block())
So it's just syntactic sugar to help developers to build some handy DSLs, which are looking like native language parts.
In this case {} means anonymous block of code. The result of invocation of code block equals to the last block's expression result.
Your code equivalent to this one
val p = double( {
print("Hello!");
5
})
Code block evaluation result is a parameter for double.
This works because block evaluation result is 5 and have Int type.
Function params evaluation doing before body of function will invoke.
First expression of code block is print and therefor print("Hello!"); will be called first. The last expression is 5 and take as function parameter.
val p = double(5)
And then print result of double is 10.
Total result of this code is printing to console
Hello!10
As aforementioned, the last expression of an anonymous block is returned; (obviously) nested anonymous blocks works as well,
val p = double {
val a = 2
val b = { println("Hello!"); 3 }
a+b
}
Hello!
p: Int = 10
Note p type conveys the return type declared for double.
Likewise,
val p = double { 2 + { println("Hello!"); 3 } }
Hello!
p: Int = 10
This is perhaps a half-baked idea, but can I copy the environment of an expression? Consider the following example:
class foo[T](block: => T) {
var data = { () => block }
def run() = { data() }
}
var a = 5
var b = new foo({ a += 1; println(a) })
var c = new foo({ a += 1; println(a) })
b.run()
c.run()
b.run()
c.run()
I get the following output:
6
7
8
9
But what I really want is the following:
6
6
7
7
In short, I want foo to have copies of the variables in the block instead of referring to them, once the initial value has been resolved. Can this be done? scala.util.DynamicVariable seems promising, but I'm having a hard time understanding how I might use it in the example above.
If you want to make a copy, then why not make a copy?
var c = new foo({ var aa = a + 1; println(aa) })
If you want to take an existing closure that refers to a variable, and turn it into a closure that refers to a copy of that variable, then I'm afraid it's not possible.
In any case, mutable variables should not be used except in very rare circumstances and in a very controlled manner. That is, not juggling their references.
I think your problem is that you're closing over a (and thus changing its value as your program runs), rather than closing over a different variable initialized from a. You might want to try something more like this:
class bar[T](block: (T) => T, a: T) {
var cur = a
def run() = { cur = block(cur); cur }
}
var a = 5
var b = new bar((r: Int) => { val q = r + 1; println(q); q }, a)
var c = new bar((r: Int) => { val q = r + 1; println(q); q }, a)
b.run()
c.run()
b.run()
c.run()
Output:
6
6
7
7
However, note that unlike your code, this will not affect the value of the a variable as it runs.
1) As n.m. already mentioned, you should prefer immutable concepts when using closures.
2) On the other hand this is exactly what closures are for. They don't capture the value of the variabe, they capture the variable itself! Your question is kinda upside-down. You actually are capturing the environment - the environment of your variable. If you don't need the same variable than copy it as n.m. or Ian McLaird respectively suggested.
I started out with Scala today, and I ran into an intriguing problem. I am running a for expression to iterate over the characters in a string, like such:
class Example {
def forString(s: String) = {
for (c <- s) {
// ...
}
}
}
and it is consistently failing with the message:
error: type mismatch;
found : Int
required: java.lang.Object
Note that implicit conversions are not applicable because they are ambiguous:
...
for (c <- s) {
^
one error found
I tried changing the loop to several things, including using the string's length and using hardcoded numbers (just for testing), but to no avail. Searching the web didn't yield anything either...
Edit: This code is the smallest I could reduce it to, while still yielding the error:
class Example {
def forString(s: String) = {
for (c <- s) {
println(String.format("%03i", c.toInt))
}
}
}
The error is the same as above, and happens at compile time. Running in the 'interpreter' yields the same.
Don't use the raw String.format method. Instead use the .format method on the implicitly converted RichString. It will box the primitives for you. i.e.
jem#Respect:~$ scala
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class Example {
| def forString(s: String) = {
| for (c <- s) {
| println("%03i".format(c.toInt))
| }
| }
| }
defined class Example
scala> new Example().forString("9")
java.util.UnknownFormatConversionException: Conversion = 'i'
Closer, but not quite. You might want to try "%03d" as your format string.
scala> "%03d".format("9".toInt)
res3: String = 009
Scala 2.81 produces the following, clearer error:
scala> class Example {
| def forString(s: String) = {
| for (c <- s) {
| println(String.format("%03i", c.toInt))
| }
| }
| }
<console>:8: error: type mismatch;
found : Int
required: java.lang.Object
Note: primitive types are not implicitly converted to AnyRef.
You can safely force boxing by casting x.asInstanceOf[AnyRef].
println(String.format("%03i", c.toInt))
^
Taking into account the other suggestion about String.format, here's the minimal fix for the above code:
scala> def forString(s: String) = {
| for (c: Char <- s) {
| println(String.format("%03d", c.toInt.asInstanceOf[AnyRef]))
| }}
forString: (s: String)Unit
scala> forString("ciao")
099
105
097
111
In this case, using the implicit format is even better, but in case you need again to call a Java varargs method, that's a solution which works always.
I tried your code (with an extra println) and it works in 2.8.1:
class Example {
| def forString(s:String) = {
| for (c <- s) {
| println(c)
| }
| }
| }
It can be used with:
new Example().forString("hello")
h
e
l
l
o