I have a List with same objects.
And I would like two sort all of them by two properties
First name (from a to Z)
Second type (numbers by ascending, like 1,2,3...)
void main() {
List<MyObject> list = List();
list.add(MyObject('Apple', 'definition of type #1'));
list.add(MyObject('Strawberry', 'definition of type #8'));
list.add(MyObject('Banana', 'definition of type #2'));
list.add(MyObject('Orange', 'definition of type #3'));
list.add(MyObject('Kiwi', 'definition of type #1'));
list.add(MyObject('Peach', 'definition of type #4'));
list.add(MyObject('Orange', 'definition of type #1'));
list.add(MyObject('Apple', 'definition of type #8'));
list.add(MyObject('Peach', 'definition of type #2'));
list.add(MyObject('Strawberry', 'definition of type #17'));
list.add(MyObject('Peach', 'definition of type #1'));
list.add(MyObject('Banana', 'definition of type #5'));
list.add(MyObject('Apple', 'definition of type #16'));
list.add(MyObject('Strawberry', 'definition of type #7'));
for (MyObject _object in list) {
print(_object.name + ' ' + _object.type);
}
RegExp regExp = new RegExp(
r"#'?.*",
);
list.sort((a, b) {
int _a = int.parse(regExp.stringMatch(a.type).replaceAll('#', ''));
int _b = int.parse(regExp.stringMatch(b.type).replaceAll('#', ''));
return _a
.compareTo(_b); //to get the order other way just switch `adate & bdate`
});
list.sort((a, b) => a.name.compareTo(b.name));
}
class MyObject {
String name;
String type;
MyObject(this.name, this.type);
}
I want output like this,
Apple #1
Apple #8
Apple #16
Banana #2
Banana #5
...
I tried to use a regex method for parsing numbers (from 'definition of type #(number)')
But If I sort list by this, I could not sort list from a to Z (name's)
You just need to sort once and define the sorting method so it compares the type if name are the same:
void main() {
List<MyObject> list = List();
list.add(MyObject('Apple', 'definition of type #1'));
list.add(MyObject('Strawberry', 'definition of type #8'));
list.add(MyObject('Banana', 'definition of type #2'));
list.add(MyObject('Orange', 'definition of type #3'));
list.add(MyObject('Kiwi', 'definition of type #1'));
list.add(MyObject('Peach', 'definition of type #4'));
list.add(MyObject('Orange', 'definition of type #1'));
list.add(MyObject('Apple', 'definition of type #8'));
list.add(MyObject('Peach', 'definition of type #2'));
list.add(MyObject('Strawberry', 'definition of type #17'));
list.add(MyObject('Peach', 'definition of type #1'));
list.add(MyObject('Banana', 'definition of type #5'));
list.add(MyObject('Apple', 'definition of type #16'));
list.add(MyObject('Strawberry', 'definition of type #7'));
RegExp regExp = new RegExp(
r"#'?.*",
);
list.sort((a, b) {
int compare = a.name.compareTo(b.name);
if (compare == 0) {
int _a = int.parse(regExp.stringMatch(a.type).replaceAll('#', ''));
int _b = int.parse(regExp.stringMatch(b.type).replaceAll('#', ''));
return _a.compareTo(_b);
} else {
return compare;
}
});
for (MyObject _object in list) {
print(_object.name + ' ' + _object.type);
}
}
class MyObject {
String name;
String type;
MyObject(this.name, this.type);
}
Output:
Apple definition of type #1
Apple definition of type #8
Apple definition of type #16
Banana definition of type #2
Banana definition of type #5
Kiwi definition of type #1
Orange definition of type #1
Orange definition of type #3
Peach definition of type #1
Peach definition of type #2
Peach definition of type #4
Strawberry definition of type #7
Strawberry definition of type #8
Strawberry definition of type #17
To do a complete comparison, you should implement Comparable< MyObject > which exposes a compareTo() method to sort by one ore more property.
See full example below :
void main() {
List<MyObject> list = List();
list.add(MyObject('Apple', 'definition of type #1'));
list.add(MyObject('Strawberry', 'definition of type #8'));
list.add(MyObject('Banana', 'definition of type #2'));
list.add(MyObject('Orange', 'definition of type #3'));
list.add(MyObject('Kiwi', 'definition of type #1'));
list.add(MyObject('Peach', 'definition of type #4'));
list.add(MyObject('Orange', 'definition of type #1'));
list.add(MyObject('Apple', 'definition of type #8'));
list.add(MyObject('Peach', 'definition of type #2'));
list.add(MyObject('Strawberry', 'definition of type #17'));
list.add(MyObject('Peach', 'definition of type #1'));
list.add(MyObject('Banana', 'definition of type #5'));
list.add(MyObject('Apple', 'definition of type #16'));
list.add(MyObject('Strawberry', 'definition of type #7'));
list.sort();
for (MyObject _object in list) {
print(_object);
}
}
abstract class Comparable {
int compareTo(Object obj){
}
}
class MyObject implements Comparable<MyObject> {
static final RegExp _regExp = RegExp(r'\D+');
final String name;
final String type;
MyObject(this.name, this.type);
#override
int compareTo(MyObject other) {
int result = name?.compareTo(other?.name) ?? 0;
if (result == 0) {
int type1 = int.tryParse(type?.replaceAll(_regExp, '') ?? 0);
int type2 = int.tryParse(other?.type?.replaceAll(_regExp, '') ?? 0);
result = type1.compareTo(type2);
}
return result;
}
#override
String toString() => '$name $type';
}
it prints
Apple definition of type #1
Apple definition of type #8
Apple definition of type #16
Banana definition of type #2
Banana definition of type #5
Kiwi definition of type #1
Orange definition of type #1
Orange definition of type #3
Peach definition of type #1
Peach definition of type #2
Peach definition of type #4
Strawberry definition of type #7
Strawberry definition of type #8
Strawberry definition of type #17
Here is an example in Dart that sorts by sector then position.
static sortBySectorPosition(List<Subclass> subclasses) {
subclasses.sort((a, b) {
if (a.sector! == b.sector!) {
return a.position!.compareTo(b.position!);
} else {
return a.sector!.compareTo(b.sector!);
}
});
}
The other answers are fine, but I'd recommend using the sorted package. It's pretty sure that it's the cleanest solution.
To make the example shorter, I'm going to assume that MyObject is the following class:
class MyObject {
const MyObject(this.firstName, this.number);
final String firstName;
final int number;
#override
String toString() => '$firstName $number';
}
You can sort Iterable<Person> like this:
final list = [
MyObject('Apple', 1),
MyObject('Strawberry', 8),
MyObject('Banana', 2),
MyObject('Orange', 3),
MyObject('Kiwi', 1),
MyObject('Peach', 4),
];
final sortedList = list.sorted(
[
SortedComparable<MyObject, String>((person) => person.firstName),
SortedComparable<MyObject, int>((person) => person.number),
],
);
print(sortedList);
Hope this helps!
Related
How can I override an abstract method with a generic type signature, and give it a more specific parameter type in a subclass?
type Rule() =
abstract Core : 'T -> bool
default _.Core _ = false
type Entity = {
Name: string
State: string
}
type Wisconsin() =
inherit Rule()
override _.Core (entity: Entity) =
entity.State = "WI"
SimpleMemberOverload.fsx(256,22): error FS0001: This expression was expected to have type
''a'
but here has type
'Entity'
You can't. After all, saying a rule takes any 'T and then having such a rule taking only entities would violate the contract. What should a caller having a reference of type Rule pointing to an object of type Wisconsin expect if e.g. a string is passed to Core?
You could however define various rules like so:
type Rule<'T> () =
abstract Core : 'T -> bool
default _.Core _ = false
type Entity = {
Name: string
State: string
}
type Wisconsin() =
inherit Rule<Entity>()
override _.Core entity =
entity.State = "WI"
meaning Wisconsin does not narrow the parameter type but now is a rule for/of entities.
According to docs you can implement multiple interfaces with object expressions. But if you see below code :
// Define two interfaces
type IFirst =
abstract F : unit -> unit
abstract G : unit -> unit
type ISecond =
abstract H : unit -> unit
abstract J : unit -> unit
// This object expression implements both interfaces.
let implementer : IFirst =
{ new ISecond with
member this.H() = ()
member this.J() = ()
interface IFirst with
member this.F() = ()
member this.G() = () }
So casting to IFirst causes a compiler error. Why is that so?
F# does not perform implicit conversions.
When type annotating in a let binding, the type must strictly match the expression.
For example,
let value : obj = new System.Collections.Generic.List<int>()
will fail to compile, even though a List is very obviously an object.
When you write:
let implementer : IFirst = expr
The type of expr must absolutely be IFirst. There's no implicit casting like in C#.
An object expression will have its type as the abstract type implemented, so:
{ new ISecond with ... }
will be inferred to have a type of ISecond. Combine it with no-implicit casts rule, and you have a compile error.
Because IFirst and ISecond are unrelated, you could (runtime) downcast to IFirst:
let firstImplementer = implementer :?> IFirst
Another option is to make a combined interface:
type IBoth = inherit IFirst inherit ISecond
and do:
let implementer =
{
new IBoth with ...
That way you can freely (static) upcast to IFirst or ISecond.
let firstImplementer = implementer :> IFirst
let secndImplementer = implementer :> ISecond
Suppose I have the following types:
type TypeA = { A: string }
type TypeB = { B: string }
and I have a union type for them both:
type MyUnionType = TypeA | TypeB
With a type just to contain the union type:
type MyContainer = { Union: MyUnionType }
now if I create an instance of one of the types in the union type:
let resultA = { A = "abc" }
when I try to assign that instance to the value in the container
let result = { Union = resultA }
the compiler complains, saying
Compilation error (line 10, col 24): This expression was expected to have type MyUnionType but here has type TypeA
but TypeA is one of the valid types specified in the union! How can I assign it to my Union property?
Here is an example of the program: https://dotnetfiddle.net/fgJKpM
In type MyUnionType = TypeA | TypeB, TypeA and TypeB do not refer to the previous TypeA and TypeB records, but are nullary constructors for the MyUnionType type. If you want them to contain values of those types you need to include them in the definition e.g.
type MyUnionType = TypeA of TypeA | TypeB of TypeB
You might want to rename the constructors to avoid confusion between them and the contained types.
you then need to supply the corresponding instance to the constructor:
let resultA = TypeA { A = "abc" }
How do I override the method Zero in the following code in such a way that I can return Euro(0) for the definiton in the type Euro
[<AbstractClass>]
type Currency () =
abstract member Zero<'T when 'T :> Currency > : unit -> 'T
type Euro (value: int) =
inherit Currency()
member this.Value = value
override this.Zero() = Euro(0) :> _
Have you tried lifting the generic constraint to the class level?
[<AbstractClass>]
type Currency<'T when 'T :> Currency<'T>>() =
abstract member Zero : unit -> 'T
type Euro (value: int) =
inherit Currency<Euro>()
member this.Value = value
override this.Zero() = Euro(0)
Though self-referencing generics always seems weird to me, this is how it'd be done in, for example, C#.
There is also the 'roll your own typeclass' technique in F#. Basically your abstract type's (instance and static) members become the fields of a 'typeclass' record, and values of that record are typeclass instances. You can have a 'euro' instance, a 'dollar' instance, and so on:
module Currency =
type t<[<Measure>] 'a> =
{ zero : decimal<'a>; from : decimal -> decimal<'a> }
/// Helper function to easily create typeclass instances for any
/// currency.
let make<[<Measure>] 'a> (curr_unit : decimal<'a>) : t<'a> =
{ zero = curr_unit - curr_unit; from = ((*) curr_unit) }
[<Measure>] type euro
let euro : t<euro> = make 1m<euro>
[<Measure>] type dollar
let dollar : t<dollar> = make 1m<dollar>
The unique thing about F# is that the type parameter that is passed to each typeclass instance can actually be a measure type, which is appropriate for currencies.
I have the following code snippets
.html
<input type = "number"
min = "0"
max = "120"
#yearsCtrl = "ngForm"
[ngFormControl] = "ageForm.controls['yearsCtrl']"
[(ngModel)] = "age.years"
id = "years">
.dart
class Age
{
int years = 0;
}
class AgeComponent {
....
AgeComponent( FormBuilder fb, ModelService
ageSrvc) {
ageForm = fb.group( {
'yearsCtrl': [''],
} );
_yearsCtrl = ageForm.controls['yearsCtrl'];
age = new Age()
}
...
}
My attempts to run the application gives the following errors (partial)
>EXCEPTION: type 'String' is not a subtype of type 'num' of 'value'. in [AST]
EXCEPTION: type 'String' is not a subtype of type 'num' of 'value'. in [AST]
(anonymous function)
ORIGINAL EXCEPTION: type 'String' is not a subtype of type 'num' of 'value'.
(anonymous function)
ORIGINAL STACKTRACE:
(anonymous function)
#0 NumberValueAccessor.writeValue (package:angular2/src/common/forms/directives/number_value_accessor.dart:38:23)
#1 setUpControl (package:angular2/src/common/forms/directives/shared.dart:34:21)
#2 NgFormControl.ngOnChanges (package:angular2/src/common/forms/directives/ng_form_control.dart:111:7)
...
It seems as if the type="num" is not being handled. I suspect the age int might be an issue also, in that it is an int but a string is required. The reverse conversion from sting back to int might also be an issue.
Any help is appreciated.
Thanks
The field needs to be of type String. Angular doesn't convert the value.
Similar to Polymer dart: Data bind integer value to String attribute
See also
How do I parse a string into a number with Dart?
Is there a better way to parse an int in Dart
A custom value accessor might help. See this Plunker for an example.
The component Address implements ControlValueAccessor with writeValue(v), registerOnChange(fn), registerOnTouched(fn)