2 same content arrays are not equal in Dart? - dart

I have a question.
When working with Dart, I can't check to see if 2 arrays are equal.
(in other languages, I can do with ==)
In fact, I just can do that == with String or number.
List arr1 = [1,2,3];
List arr2 = [1,2,3];
if (arr1 == arr2) {
print("equal");
} else {
print("not equal");
}
// Output: not equal.
So I wonder how does that make sense. I mean, How we can do if the == is just work for the cases of String or number (if the values compared are the same).
How do I have to do if I want to check that kind of comparison (equal) for List, Map, ..
It just work for String & number.

arr1 and arr2 are different instances of an object of type List. By default different instances are always different.
When a class implements a custom == operator it can override this behavior. Some classes have a custom implementation by default like int and String.
This can easily be done for immutable objects but not for mutable. One reason is that usually the hashCode is calculated from the values stroed in a class and the hashCode must not change for an instance because this can for example cause that an instance stored in a map can't be retrieved anymore when the hashcode of the key changed.
As a workaround there is a library that provides helper functions to compare lists/iterables.
import 'package:collection/equality.dart';
void main(List<String> args) {
if (const IterableEquality().equals([1,2,3],[1,2,3])) {
// if (const SetEquality().equals([1,2,3].toSet(),[1,2,3].toSet())) {
print("Equal");
} else {
print("Not equal");
}
}

Related

In dart, is Map treated as a value type?

I have heard that all data types in dart are reference types, but some fairly primitive ones such as int behave as value types. Does Map behave as a value type?
I had wrapped a class around my Map and it worked:
final manageVgnItmFormsProvider = Provider.autoDispose<VgnItmForms>((provider) {
return VgnItmForms();
});
class VgnItmForms {
late Map<String, VgnItmFormVm> forms;
VgnItmForms();
}
And I changed it to:
final manageVgnItmFormsProvider = Provider.autoDispose<Map>((provider) {
var forms = {};
return forms;
});
And then the forms Map kept going back to being an empty Map after I had set it to a populated Map elsewhere. I think it is getting lost because Map is treated as a value type and before my class was treated as a reference type.

Dart equatable with non final variables

I have class with final variable (hash) and some other non-final variables.
Hash is unique value. And objects are stored in Set. Set uses '==' operand to check equality of objects. I want to override "==" and "hashCode" in my class and work with Set array.
To avoid using boilerplate code I want to use Equatable extension. Like this
class User extends Equatable {
final String hash;
String balance;
bool state;
....
#override
List<Object> get props => [hash];
} .... Set<User> users
Is it correct way to use Equatable in my case, 'cause it is uses with immutable classes.
Thanks!
Overriding hashCode to depend on non-final fields is usually not recommended because it can make Sets and Maps and other data structures that depend on hashCode internally inconsistent. Suppose you have such an object and insert it into a Set. Later, you mutate that object by assigning a new value to that field, but the Set would still have a reference to that object with the old hash code. For example, consider:
class Foo {
String s;
Foo(this.s);
#override
bool operator ==(Object other) {
return other is Foo && s == other.s;
}
#override
int get hashCode => s.hashCode;
#override
String toString() => s;
}
void main() {
var foo = Foo('foo');
var someSet = <Foo>{foo};
foo.s = 'bar';
print(someSet.contains(foo)); // Prints: false
someSet.add(foo);
print(someSet.length); // Prints: 2
print(someSet); // Prints: {bar, bar}
}
and now someSet would have two references to the exact same object, which violates its goal of storing unique objects.
A Map would have similar problems.
Since hashCode is tied to operator ==, this consequently also means that you usually shouldn't override operator == to depend on non-final fields.
You can get away with it if you can guarantee that you never mutate your objects while they're being referenced by a Set/Map/etc. or if you can guarantee that whenever you want to add your object to a Set/Map/etc. that you create a copy of your object and add that copy instead.
I'd say your use is correct.
You use Equatable only with the final field, so the equality and hash code should be stable over time, and the hash field is unique, so it can serve as identifier for the object.
If your hash field ends up not unique, you'll have two distinguishable objects that are equal, so ... don't do that.
Not sure how much you gain from using Equatable, though. If you wrote the equality and hash code yourself, it would just be:
bool operator==(Object other) => other is Foo && hash == other.hash;
int get hashCode => hash.hashCode;

Using an 'is' expression when the right-hand operand is a variable?

I am trying to write a function that takes two arguments: givenType and targetType. If these two arguments match, I want givenType to be returned, otherwise null.
For this objective, I am trying to utilize Dart's is expression (maybe there is a better way to go about it, I am open to suggestions). Initially, I thought it would be as simple as writing this:
matchesTarget(givenType, targetType) {
if (givenType is targetType) {
return givenType;
}
return null;
}
But this produces an error:
The name 'targetType' isn't a type and can't be used in an 'is'
expression. Try correcting the name to match an existing
type.dart(type_test_with_non_type)
I tried looking up what satisfies an is expression but cannot seem to find it in the documentation. It seems like it needs its right-hand operand to be known at compile-time (hoping this is wrong, but it does not seem like I can use a variable), but if so, how else can I achieve the desired effect?
I cant guess the purpose of the function (or the scenario where it would be used, so if you can clarify it would be great). First of all, I don't know if you are passing "types" as arguments. And yes, you need to specify in compile time the right hand argument of the is function.
Meanwhile, if you are passing types, with one change, you can check if the types passed to your function at runtime.
matchesTarget(Type givenType, Type targetType) {
print('${givenType.runtimeType} ${targetType.runtimeType}');
if (givenType == targetType) {
return givenType;
}
return null;
}
main(){
var a = int; //this is a Type
var b = String; //this is also a Type
print(matchesTarget(a,b)); //You are passing different Types, so it will return null
var c = int; //this is also a Type
print(matchesTarget(a,c)); //You are passing same Types, so it will return int
}
But if you are passing variables, the solution is pretty similar:
matchesTarget(givenVar, targetVar) {
print('${givenVar.runtimeType} ${targetVar.runtimeType}');
if (givenVar.runtimeType == targetVar.runtimeType) {
return givenVar.runtimeType;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = "hello"; //this is also a variable (String)
print(matchesTarget(a,b)); //this will return null
var c = 12; //this is also a variable (int)
print(matchesTarget(a,c)); //this will return int
}
The Final Answer
matchesTarget(givenVar, targetType) {
print('${givenVar.runtimeType} ${targetType}');
if (givenVar.runtimeType == targetType) {
return givenVar;
}
return null;
}
main(){
var a = 10; //this is a variable (int)
var b = String; //this is a type (String)
print(matchesTarget(a,b)); //this will return null because 'a' isnt a String
var c = int; //this is also a type (int)
print(matchesTarget(a,c)); //this will return the value of 'a' (10)
}
The as, is, and is! operators are handy for checking types at runtime.
The is operator in Dart can be only used for type checking and not checking if two values are equal.
The result of obj is T is true if obj implements the interface specified by T. For example, obj is Object is always true.
See the below code for an example of how to use the is operator
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
Even the error message that you're getting says that
The name 'targetType' isn't a type and can't be used in an 'is'
expression.
So the bottomline is that you can use is only for checking if a variable or value belongs to a particular data type.
For checking equality, you can use the == operator if comparing primitive types, or write your own method for comparing the values. Hope this helps!

How would I properly format this Swift function to map an array?

I'm trying to build a function with swift that will map an array, divide each value in the array by 3, then spit out a new array. This is what I have so far:
func divideby3Map<T, U>(y: [T], z: T -> U) -> [U] {
let array = [int]()
let divideby3Array = array.map { [y] / 3 }
return dividedby3Array
}
divideby3Map([1,2,3,4,5])
Where T and U are the original array, and the new array being returned respectively, and it's done using generics.
I'm sure this isn't written properly, I'm stuck in terms of the right syntax. For example, since the array being returned is represented by the generic [U], I assume I have to use it somewhere in the array being returned, not sure where though.
When writing a generic function, it’s sometimes easier to approach it in 3 steps: first write the code stand-alone using a specific type. Then write the code as a function, still with a specific type. Finally, change the function to be generic.
The first part, dividing an array by 3, can be done like this:
let a = [1,2,3,4,5]
// map is run on the array of integers, and returns a new
// array with the operation performed on each element in a:
let b = a.map { $0 / 3 }
// so b will be [0,0,1,1,1]
// (don’t forget, integer division truncates)
Note the closure you provide between the { } is an operation that will be applied to each element of the array. $0 represents the element, and you divide it by 3. You could also write it as a.map { i in i / 3 }.
To put this into its own function:
func divideby3Map(source: [Int]) -> [Int] {
return source.map { $0 / 3 }
}
No need to declare a fresh array – map will create one for you. You can then return that directly (you can assign it to a temporary if you prefer, but that isn’t really necessary).
Finally, if you want to make it generic, start by adding a placeholder:
func divideby3Map<T>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
Note, there’s only a need for one placeholder, T, because you are returning the exact same type you are passed in.
Except… this won’t compile, because the compiler doesn’t know that T is guaranteed to provide two critical things: the ability to divide (a / operator), and the ability to create new T from integer literals (i.e. to create a T with value 3 to divide by). Otherwise, what if we passed an array of strings or an array of arrays in?
To do this, we need to “constrain” T so our function will only accept as arguments types that provide these features. One such protocol we can use to constrain T is IntegerType, which does guarantee these features (as well as some other ones like +, * etc):
func divideby3Map<T: IntegerType>(source: [T]) -> [T] {
return source.map { $0 / 3 }
}
divideby3Map(a) // returns [0,0,1,1,1]
let smallInts: [UInt8] = [3,6,9]
divideby3Map(smallInts) // returns [1,2,3]

Why to use tuples when we can use array to return multiple values in swift

Today I was just going through some basic swift concepts and was working with some examples to understand those concepts. Right now I have completed studying tuples.
I have got one doubt i.e, what is the need of using tuples ? Ya I did some digging on this here is what I got :
We can be able to return multiple values from a function. Ok but we can also do this by returning an array.
Array ok but we can return an multiple values of different types. Ok cool but this can also be done by array of AnyObject like this :
func calculateStatistics (scores:[Int])->[AnyObject]
{
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores
{
if score > max{
max = score
}
else if score < min{
min = score
}
sum += score
}
return [min,max,"Hello"]
}
let statistics = calculateStatistics([25,39,78,66,74,80])
var min = statistics[0]
var max = statistics[1]
var msg = statistics[2] // Contains hello
We can name the objects present in the tuples. Ok but I can use a dictionary of AnyObject.
I am not saying that Why to use tuples when we have got this . But there should be something only tuple can be able to do or its easy to do it only with tuples. Moreover the people who created swift wouldn't have involved tuples in swift if there wasn't a good reason. So there should have been some good reason for them to involve it.
So guys please let me know if there's any specific cases where tuples are the best bet.
Thanks in advance.
Tuples are anonymous structs that can be used in many ways, and one of them is to make returning multiple values from a function much easier.
The advantages of using a tuple instead of an array are:
multiple types can be stored in a tuple, whereas in an array you are restricted to one type only (unless you use [AnyObject])
fixed number of values: you cannot pass less or more parameters than expected, whereas in an array you can put any number of arguments
strongly typed: if parameters of different types are passed in the wrong positions, the compiler will detect that, whereas using an array that won't happen
refactoring: if the number of parameters, or their type, change, the compiler will produce a relevant compilation error, whereas with arrays that will pass unnoticed
named: it's possible to associate a name with each parameter
assignment is easier and more flexible - for example, the return value can be assigned to a tuple:
let tuple = functionReturningTuple()
or all parameters can be automatically extracted and assigned to variables
let (param1, param2, param3) = functionReturningTuple()
and it's possible to ignore some values
let (param1, _, _) = functionReturningTuple()
similarity with function parameters: when a function is called, the parameters you pass are actually a tuple. Example:
// SWIFT 2
func doSomething(number: Int, text: String) {
println("\(number): \(text)")
}
doSomething(1, "one")
// SWIFT 3
func doSomething(number: Int, text: String) {
print("\(number): \(text)")
}
doSomething(number: 1, text: "one")
(Deprecated in Swift 2) The function can also be invoked as:
let params = (1, "one")
doSomething(params)
This list is probably not exhaustive, but I think there's enough to make you favor tuples to arrays for returning multiple values
For example, consider this simple example:
enum MyType {
case A, B, C
}
func foo() -> (MyType, Int, String) {
// ...
return (.B, 42, "bar")
}
let (type, amount, desc) = foo()
Using Array, to get the same result, you have to do this:
func foo() -> [Any] {
// ...
return [MyType.B, 42, "bar"]
}
let result = foo()
let type = result[0] as MyType, amount = result[1] as Int, desc = result[2] as String
Tuple is much simpler and safer, isn't it?
Tuple is a datastructure which is lighter weight than heterogeneous Array. Though they're very similar, in accessing the elements by index, the advantage is tuples can be constructed very easily in Swift. And the intention to introduce/interpolate this(Tuple) data structure is Multiple return types. Returning multiple data from the 'callee' with minimal effort, that's the advantage of having Tuples. Hope this helps!
A tuple is ideally used to return multiple named data from a function for temporary use. If the scope of the tuple is persistent across a program you might want to model that data structure as a class or struct.

Resources