I have a slight issue. I have a model class which has a list. Inside the list is another list which I need to implement a summation of integers. I keep getting this range error issue from my dart code when implemented with a for loop. Whats the cleanest way to achieve this summation?
Main.dart
int totalSpendAmount = 0;
int totalSpendQuantity = 0;
List<int> spendList = [];
List<int> quantityList = [];
#override
Widget build(BuildContext context) {
return ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: widget.materials != null ? widget.materials.length : 0,
itemBuilder: (BuildContext context, int index) {
amountPlan = FlutterMoneyFormatter(
amount: (widget.materials[index].budget.toDouble()))
.output;
//for loop to calculate all purchases for amount and quantity spent
for (var i = 0; i < widget.materials.length; i++) {
if(widget.materials[index].purchase!=null){
widget.materials.forEach((e) => totalSpendAmount += e.purchase[index].amount);
}
spendList.add(totalSpendAmount);
}
Model Class
class Materials {
String id;
String title;
String brand;
String measurementUnit;
int proposedQuantity;
int budget;
int quantityInStore;
int quantityUsed;
int unitCost;
bool approved;
String createdAt;
String updatedAt;
String taskId;
List<Purchase> purchase;
Materials(
{this.id,
this.title,
this.brand,
this.measurementUnit,
this.proposedQuantity,
this.budget,
this.quantityInStore,
this.quantityUsed,
this.unitCost,
this.approved,
this.createdAt,
this.updatedAt,
this.taskId,
this.purchase});
static List<Materials> fromJsonList(List<dynamic> _list) {
return _list.map((_tasks) => Materials.fromJson(_tasks)).toList();
}
}
class Purchase {
String id;
int quantity;
int amount;
int discount;
String receipt;
String materialId;
String projectId;
String createdAt;
String updatedAt;
String purchasedBy;
Purchase(
{this.id,
this.quantity,
this.amount,
this.discount,
this.receipt,
this.materialId,
this.projectId,
this.createdAt,
this.updatedAt,
this.purchasedBy});
}
I need a list of all summation of amount integer inside the Purchase object for materials indexes which would be passed inside my ListView.Builder's widget
You can achieve this using fold method. You can check this documentation
https://api.dart.dev/stable/1.10.1/dart-core/List/fold.html
Related
I am trying to pass 5th element of an array(Products[]) of class product to another function. The goal is to update the information of the element Product[5]. Everything seems to work fine except information of Product[5] variable is not updating.
Update: Problem solved by removing while(!EOF), thanks to Remy Lebeau.
The relevant part of Class:
class product
{
private:
float Wholesale_Price = 0;
float Retail_Price = 0;
string Supplier = "N/A";
string Note = "N/A";
int Stock_Amount = 0;
public:
string Name="N/A";
void UpdateRetailPrice(float New_Retail_Price)
{
Retail_Price = New_Retail_Price;
}
void UpdateProductAmount(int New_Stock_Amount)
{
Stock_Amount = New_Stock_Amount;
}
void UpdateWholesale_price(float New_Wholesale_Price)
{
Wholesale_Price = New_Wholesale_Price;
}
};
The relevant part of function:
void ReadProductFromFile(product* Products)
{
string Name, Supplier, Note, Wholesale_Price, Retail_Price, Stock_Amount;//wholesale price, stock amount,price are in string so that
//it becomes easy to use getline(). Use stoi() later for turning string to int.
ifstream ReadProductFromFile;
ReadProductFromFile.open("product.txt");
if (!ReadProductFromFile)
{
perror("Product File failed to open");
return;
}
while(!EOF)
{
/*read product info txt file------>*/
getline(ReadProductFromFile, Name);
getline(ReadProductFromFile, Wholesale_Price);
getline(ReadProductFromFile, Retail_Price);
getline(ReadProductFromFile, Stock_Amount);
/*update product info---------->*/
Products->Name = Name;
Products->UpdateWholesale_price(stoi(Wholesale_Price));
Products->UpdateProductAmount(stoi(Stock_Amount));
Products->UpdateRetailPrice(stoi(Retail_Price));
}
}
Relevant part of Main function:
int main(int argc, char const *argv[])
{
product Products[10];
ReadProductFromFile(Products+5);//is this the right way to send Products[5]? tried &(product[5]) but error
return 0;
}
Input:
Bananas
210
270
310
I have a list of objects of the same class.
This class contains an attribute I want to use.
I would like to get a list of all these attributes in one line. Is this possible?
Here is a small example: I just want a list of all the colors.
It is important that I return directly a list of these attributes, without the normal forEach statement.
void main() {
List<Car> listOfCars = [
Car('blue'),
Car('green'),
Car('yellow'),
];
}
//List<String> listOfColors = listOfCars[all].color;
class Car{
String color;
Car(this.color);
}
You can use the map function to achieve this
List<String> listOfColors = listOfCars.map((car) => car.color).toList();
print(listOfColors);
Just check out this code below:
void main() {
List<Car> listOfCars = [
Car('blue'),
Car('green'),
Car('yellow'),
];
List<String> stringList = List();
// This is where you get the single car object and then you add it the list of string
for (int i = 0; i < listOfCars.length; i++) {
stringList.add(listOfCars[i].color);
}
// this is the desired out put i have just printed your list :
print('This is the string length : ' + stringList.length.toString());
for (int i = 0; i < stringList.length; i++) {
print('This is the string list :' + stringList[i]);
}
}
class Car {
final String color;
Car(this.color);
}
Blow is the output :
This is the string length : 3
This is the string list :blue
This is the string list :green
This is the string list :yellow
How to sort a list of objects by the alphabetical order of one of its properties (Not the name but the actual value the property holds)?
You can pass a comparison function to List.sort.
someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));
In general, you can provide a custom comparison function to List.sort.
/// Desired relation | Result
/// -------------------------------------------
/// a < b | Returns a negative value.
/// a == b | Returns 0.
/// a > b | Returns a positive value.
///
int mySortComparison(SomeClass a, SomeClass b) {
final propertyA = someProperty(a);
final propertyB = someProperty(b);
if (propertyA < propertyB) {
return -1;
} else if (propertyA > propertyB) {
return 1;
} else {
return 0;
}
}
list.sort(mySortComparison);
If you're sorting some custom class you own, you alternatively could make your class implement the Comparable interface:
class MyCustomClass implements Comparable<MyCustomClass> {
...
#override
int compareTo(MyCustomClass other) {
if (someProperty < other.someProperty) {
return -1;
} else if (someProperty > other.someProperty) {
return 1;
} else {
return 0;
}
}
}
and then you can use list.sort() directly without supplying a callback.
Note that if you're sorting by a single property that already implements the Comparable interface, implementing the comparison functions is much simpler. For example:
class MyCustomClass implements Comparable<MyCustomClass> {
...
#override
int compareTo(MyCustomClass other) =>
someProperty.compareTo(other.someProperty);
}
Reversing
If you want to reverse the sort order, you can:
Make your comparison function return a value with the opposite sign.
Alternatively just explicitly reverse the list after sorting:
list = (list..sort()).reversed.toList();
Sorting by multiple properties (a.k.a. subsorting)
There are a variety of ways to sort by multiple properties.
A general way is to perform a stable sort for each property in reverse order of importance. For example, if you want to sort names primarily by surname and then subsort within surnames by given name, then you would first sort by given names, and then perform a stable sort by surname. See below for how to perform a stable sort.
Alternatively, you could sort with a comparison function that itself checks multiple properties. For example:
class Name {
Name({String? surname, String? givenName})
: surname = surname ?? "",
givenName = givenName ?? "";
final String surname;
final String givenName;
}
int compareNames(Name name1, Name name2) {
var comparisonResult = name1.surname.compareTo(name2.surname);
if (comparisonResult != 0) {
return comparisonResult;
}
// Surnames are the same, so subsort by given name.
return name1.givenName.compareTo(name2.givenName);
}
package:collection provides an extension to chain comparison functions so that combining them is a bit more straightforward and less error-prone:
import 'package:collection/collection.dart';
int compareSurnames(Name name1, Name name2) =>
name1.surname.compareTo(name2.surname);
int compareGivenNames(Name name1, Name name2) =>
name1.givenName.compareTo(name2.givenName);
final compareNames = compareSurnames.then(compareGivenNames);
My dartbag package also provides a compareIterables function that allows comparing Lists of property values in order of importance:
import 'package:dartbag/collection.dart';
int compareNames(Name name1, Name name2) =>
compareIterables(
[name1.surname, name1.givenName],
[name2.surname, name2.givenName],
);
Okay, I want a stable sort
List.sort is not guaranteed to be a stable sort. If you need a stable sort, package:collection provides insertionSort and mergeSort implementations that are stable.
But comparing might be expensive
Suppose you have a custom comparison function that looks something like:
int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
var a0 = computeValue(a);
var b0 = computeValue(b);
return a0.compareTo(b0);
}
The sorting process might call computeValue multiple times for the same object, which is particularly wasteful if computeValue() is expensive. In such cases, a Schwartzian transform could be faster (at the expense of using more memory). This approach maps your objects to directly sortable keys, sorts those keys, and extracts the original objects. (This is how Python's sort and sorted functions work.)
Here's one possible implementation:
class _SortableKeyPair<T, K extends Comparable<Object>>
implements Comparable<_SortableKeyPair<T, K>> {
_SortableKeyPair(this.original, this.key);
final T original;
final K key;
#override
int compareTo(_SortableKeyPair<T, K> other) => key.compareTo(other.key);
}
/// Returns a sorted *copy* of [items] according to the computed sort key.
List<E> sortedWithKey<E, K extends Comparable<Object>>(
Iterable<E> items,
K Function(E) toKey,
) {
final keyPairs = [
for (var element in items) _SortableKeyPair(element, toKey(element)),
]..sort();
return [
for (var keyPair in keyPairs) keyPair.original,
];
}
void main() {
final list = <MyCustomClass>[ ... ];
final sorted = sortedWithKeys(list, computeValue);
}
My dartbag package provides such a sortWithKey function (and also a sortWithAsyncKey function if the key needs to be generated asynchronously).
If you want to sort the object "objects" by the property "name" do something like this
objects.sort((a, b) {
return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});
Immutable extension sortedBy for List.
extension MyIterable<E> on Iterable<E> {
Iterable<E> sortedBy(Comparable key(E e)) =>
toList()..sort((a, b) => key(a).compareTo(key(b)));
}
And use
list.sortedBy((it) => it.name);
Here is my contribution to this good question. If someone is facing difficulty to understand how the #Nate Bosch answer is working & you want to sort your custom model class list then you can do this way.
1. You have to implement Comparable abstract class in your model class.
It has the method compareTo which you have to override.
For example, I have this StudentMarks model class which has marks property in it.
class StudentMarks implements Comparable {
int marks;
StudentMarks({
this.marks,
});
#override
int compareTo(other) {
if (this.marks == null || other == null) {
return null;
}
if (this.marks < other.marks) {
return 1;
}
if (this.marks > other.marks) {
return -1;
}
if (this.marks == other.marks) {
return 0;
}
return null;
}
}
2. Now you can call compareTo method inside the sort method.
void _sortStudents({bool reversed: false}) {
_students.sort((a, b) {
return a.compareTo(b);
});
if (reversed) {
_students = _students.reversed.toList();
}
setState(() {});
}
Refer to this link you want to know more about the Comparable class
https://api.dart.dev/stable/2.1.0/dart-core/Comparable-class.html
Its worked for me:
myList..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
Using Comparatorfunction, sort Users by id.
Comparator<UserModel> sortById = (a, b) => a.id.compareTo(b.id);
users.sort(sortById);
Now we can sort it in reversed/descending order.
users = users.reversed.toList();
To sort it in reverse order :
list.sort((a, b) {
return b.status.toLowerCase().compareTo(a.status.toLowerCase());
});
What's more, you can use Comparable.compare for more clear, for example:
class _Person {
final int age;
final String name;
_Person({required this.age, required this.name});
}
void _test() {
final array = [
_Person(age: 10, name: 'Dean'),
_Person(age: 20, name: 'Jack'),
_Person(age: 30, name: 'Ben'),
];
// ascend with age
// Dean Jack Ben
array.sort((p1, p2) {
return Comparable.compare(p1.age, p2.age);
});
// decend with age
// Ben Jack Dean
array.sort((p1, p2) {
return Comparable.compare(p2.age, p1.age);
});
// ascend with name
// Ben Dean Jack
array.sort((p1, p2) {
return Comparable.compare(p1.name, p2.name);
});
}
Similar to #pavel-shorokhovs answer, but strongly typed:
extension IterableExtensions<T> on Iterable<T> {
Iterable<T> sortBy<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
toList()..sort((a, b) => selector(a).compareTo(selector(b)));
Iterable<T> sortByDescending<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
sortBy(selector).toList().reversed;
}
i had fpgrowth machine learning output/result with each element of list contains another list and frequency field i was to sort by frequency in descending order so i used a bit of recursion for that try it might work i know i am late but i am posting maybe someone else could benefit.
sort(List<FrequentItem> fqItems) {
int len = fqItems.length;
if(len==2){
if(fqItems[0].frequency>fqItems[1].frequency){
sortedItems.add(fqItems[0]);
sortedItems.add(fqItems[1]);
}else{
sortedItems.add(fqItems[1]);
sortedItems.add(fqItems[0]);
}
return;
}else{
FrequentItem max = fqItems[0];
int index =0;
for(int i=0;i<len-2;i++){
if(max.frequency<fqItems[i+1].frequency){
max = fqItems[i+1];
index = i+1;
}
}
sortedItems.add(max);
fqItems.removeAt(index);
sort(fqItems);
}
}
Step 1: Add compareTo method to class:
class Student {
String? name;
int? age;
Student({this.name, this.age});
int getAge() {
if (age == null) return 0;
return age!;
}
#override
int compareTo(Student other) {
var a = getAge();
var b = other.getAge();
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}
}
Step 2: Sorting your list:
By ascending:
studentList.sort((a, b) {
return a.compareTo(b);
});
By descending:
studentList.sort((a, b) {
return b.compareTo(a);
});
How to sort a list of objects by the alphabetical order of one of its properties (Not the name but the actual value the property holds)?
You can pass a comparison function to List.sort.
someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));
In general, you can provide a custom comparison function to List.sort.
/// Desired relation | Result
/// -------------------------------------------
/// a < b | Returns a negative value.
/// a == b | Returns 0.
/// a > b | Returns a positive value.
///
int mySortComparison(SomeClass a, SomeClass b) {
final propertyA = someProperty(a);
final propertyB = someProperty(b);
if (propertyA < propertyB) {
return -1;
} else if (propertyA > propertyB) {
return 1;
} else {
return 0;
}
}
list.sort(mySortComparison);
If you're sorting some custom class you own, you alternatively could make your class implement the Comparable interface:
class MyCustomClass implements Comparable<MyCustomClass> {
...
#override
int compareTo(MyCustomClass other) {
if (someProperty < other.someProperty) {
return -1;
} else if (someProperty > other.someProperty) {
return 1;
} else {
return 0;
}
}
}
and then you can use list.sort() directly without supplying a callback.
Note that if you're sorting by a single property that already implements the Comparable interface, implementing the comparison functions is much simpler. For example:
class MyCustomClass implements Comparable<MyCustomClass> {
...
#override
int compareTo(MyCustomClass other) =>
someProperty.compareTo(other.someProperty);
}
Reversing
If you want to reverse the sort order, you can:
Make your comparison function return a value with the opposite sign.
Alternatively just explicitly reverse the list after sorting:
list = (list..sort()).reversed.toList();
Sorting by multiple properties (a.k.a. subsorting)
There are a variety of ways to sort by multiple properties.
A general way is to perform a stable sort for each property in reverse order of importance. For example, if you want to sort names primarily by surname and then subsort within surnames by given name, then you would first sort by given names, and then perform a stable sort by surname. See below for how to perform a stable sort.
Alternatively, you could sort with a comparison function that itself checks multiple properties. For example:
class Name {
Name({String? surname, String? givenName})
: surname = surname ?? "",
givenName = givenName ?? "";
final String surname;
final String givenName;
}
int compareNames(Name name1, Name name2) {
var comparisonResult = name1.surname.compareTo(name2.surname);
if (comparisonResult != 0) {
return comparisonResult;
}
// Surnames are the same, so subsort by given name.
return name1.givenName.compareTo(name2.givenName);
}
package:collection provides an extension to chain comparison functions so that combining them is a bit more straightforward and less error-prone:
import 'package:collection/collection.dart';
int compareSurnames(Name name1, Name name2) =>
name1.surname.compareTo(name2.surname);
int compareGivenNames(Name name1, Name name2) =>
name1.givenName.compareTo(name2.givenName);
final compareNames = compareSurnames.then(compareGivenNames);
My dartbag package also provides a compareIterables function that allows comparing Lists of property values in order of importance:
import 'package:dartbag/collection.dart';
int compareNames(Name name1, Name name2) =>
compareIterables(
[name1.surname, name1.givenName],
[name2.surname, name2.givenName],
);
Okay, I want a stable sort
List.sort is not guaranteed to be a stable sort. If you need a stable sort, package:collection provides insertionSort and mergeSort implementations that are stable.
But comparing might be expensive
Suppose you have a custom comparison function that looks something like:
int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
var a0 = computeValue(a);
var b0 = computeValue(b);
return a0.compareTo(b0);
}
The sorting process might call computeValue multiple times for the same object, which is particularly wasteful if computeValue() is expensive. In such cases, a Schwartzian transform could be faster (at the expense of using more memory). This approach maps your objects to directly sortable keys, sorts those keys, and extracts the original objects. (This is how Python's sort and sorted functions work.)
Here's one possible implementation:
class _SortableKeyPair<T, K extends Comparable<Object>>
implements Comparable<_SortableKeyPair<T, K>> {
_SortableKeyPair(this.original, this.key);
final T original;
final K key;
#override
int compareTo(_SortableKeyPair<T, K> other) => key.compareTo(other.key);
}
/// Returns a sorted *copy* of [items] according to the computed sort key.
List<E> sortedWithKey<E, K extends Comparable<Object>>(
Iterable<E> items,
K Function(E) toKey,
) {
final keyPairs = [
for (var element in items) _SortableKeyPair(element, toKey(element)),
]..sort();
return [
for (var keyPair in keyPairs) keyPair.original,
];
}
void main() {
final list = <MyCustomClass>[ ... ];
final sorted = sortedWithKeys(list, computeValue);
}
My dartbag package provides such a sortWithKey function (and also a sortWithAsyncKey function if the key needs to be generated asynchronously).
If you want to sort the object "objects" by the property "name" do something like this
objects.sort((a, b) {
return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});
Immutable extension sortedBy for List.
extension MyIterable<E> on Iterable<E> {
Iterable<E> sortedBy(Comparable key(E e)) =>
toList()..sort((a, b) => key(a).compareTo(key(b)));
}
And use
list.sortedBy((it) => it.name);
Here is my contribution to this good question. If someone is facing difficulty to understand how the #Nate Bosch answer is working & you want to sort your custom model class list then you can do this way.
1. You have to implement Comparable abstract class in your model class.
It has the method compareTo which you have to override.
For example, I have this StudentMarks model class which has marks property in it.
class StudentMarks implements Comparable {
int marks;
StudentMarks({
this.marks,
});
#override
int compareTo(other) {
if (this.marks == null || other == null) {
return null;
}
if (this.marks < other.marks) {
return 1;
}
if (this.marks > other.marks) {
return -1;
}
if (this.marks == other.marks) {
return 0;
}
return null;
}
}
2. Now you can call compareTo method inside the sort method.
void _sortStudents({bool reversed: false}) {
_students.sort((a, b) {
return a.compareTo(b);
});
if (reversed) {
_students = _students.reversed.toList();
}
setState(() {});
}
Refer to this link you want to know more about the Comparable class
https://api.dart.dev/stable/2.1.0/dart-core/Comparable-class.html
Its worked for me:
myList..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));
Using Comparatorfunction, sort Users by id.
Comparator<UserModel> sortById = (a, b) => a.id.compareTo(b.id);
users.sort(sortById);
Now we can sort it in reversed/descending order.
users = users.reversed.toList();
To sort it in reverse order :
list.sort((a, b) {
return b.status.toLowerCase().compareTo(a.status.toLowerCase());
});
What's more, you can use Comparable.compare for more clear, for example:
class _Person {
final int age;
final String name;
_Person({required this.age, required this.name});
}
void _test() {
final array = [
_Person(age: 10, name: 'Dean'),
_Person(age: 20, name: 'Jack'),
_Person(age: 30, name: 'Ben'),
];
// ascend with age
// Dean Jack Ben
array.sort((p1, p2) {
return Comparable.compare(p1.age, p2.age);
});
// decend with age
// Ben Jack Dean
array.sort((p1, p2) {
return Comparable.compare(p2.age, p1.age);
});
// ascend with name
// Ben Dean Jack
array.sort((p1, p2) {
return Comparable.compare(p1.name, p2.name);
});
}
Similar to #pavel-shorokhovs answer, but strongly typed:
extension IterableExtensions<T> on Iterable<T> {
Iterable<T> sortBy<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
toList()..sort((a, b) => selector(a).compareTo(selector(b)));
Iterable<T> sortByDescending<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
sortBy(selector).toList().reversed;
}
i had fpgrowth machine learning output/result with each element of list contains another list and frequency field i was to sort by frequency in descending order so i used a bit of recursion for that try it might work i know i am late but i am posting maybe someone else could benefit.
sort(List<FrequentItem> fqItems) {
int len = fqItems.length;
if(len==2){
if(fqItems[0].frequency>fqItems[1].frequency){
sortedItems.add(fqItems[0]);
sortedItems.add(fqItems[1]);
}else{
sortedItems.add(fqItems[1]);
sortedItems.add(fqItems[0]);
}
return;
}else{
FrequentItem max = fqItems[0];
int index =0;
for(int i=0;i<len-2;i++){
if(max.frequency<fqItems[i+1].frequency){
max = fqItems[i+1];
index = i+1;
}
}
sortedItems.add(max);
fqItems.removeAt(index);
sort(fqItems);
}
}
Step 1: Add compareTo method to class:
class Student {
String? name;
int? age;
Student({this.name, this.age});
int getAge() {
if (age == null) return 0;
return age!;
}
#override
int compareTo(Student other) {
var a = getAge();
var b = other.getAge();
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}
}
Step 2: Sorting your list:
By ascending:
studentList.sort((a, b) {
return a.compareTo(b);
});
By descending:
studentList.sort((a, b) {
return b.compareTo(a);
});
I have a hazelcast Ilist,The student class contains 5 properties like(id,name,address,number,school).Now there are 10k records in the list,how can I find the student whose name is tony and number is 001 quickly except for for loop.I hnow if it is a Imap I can use predicate to filter ,but it is a list ,I didn't find a predicate for Ilist.Any help ,thanks a lot.
Unfortunately there is no way to do this with some kind of a predicate or other magic. You have to do a loop. To speed it up, however, you should run this search on the member that contains the list. Partitioning is defined by the name of the list though. You can basically write yourself a small "query engine" to utilize the Hazelcast predicates on top of a list.
I created a basic example, you can most probably optimize it though.
A simple student class:
public class Student implements Serializable {
private long id;
private String name;
private String address;
private String number;
private String school;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public String getSchool() { return school; }
public void setSchool(String school) { this.school = school; }
#Override
public String toString() {
return "Student{" + "id=" + id
+ ", name='" + name + '\''
+ ", address='" + address + '\''
+ ", number='" + number + '\''
+ ", school='" + school + '\'' + '}';
}
}
The search executor:
public class StudentSearch {
private final IExecutorService executorService;
public StudentSearch(HazelcastInstance hazelcastInstance) {
this.executorService =
hazelcastInstance.getExecutorService("student_search");
}
public Student findFirstByNameAndNumber(String listName,
String name,
String number)
throws Exception {
Predicate namePredicate = Predicates.equal("name", name);
Predicate numberPredicate = Predicates.equal("number", number);
Predicate predicate = Predicates.and(namePredicate, numberPredicate);
StudentSearchTask task = new StudentSearchTask(listName, predicate);
Future<Student> future = executorService.submitToKeyOwner(task, listName);
return future.get();
}
private static class StudentSearchTask
implements Callable<Student>,
DataSerializable,
HazelcastInstanceAware {
private HazelcastInstance hazelcastInstance;
private String listName;
private Predicate predicate;
public StudentSearchTask() {
}
public StudentSearchTask(String listName, Predicate predicate) {
this.listName = listName;
this.predicate = predicate;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
#Override
public Student call() throws Exception {
IList<Student> list = hazelcastInstance.getList(listName);
Optional<Map.Entry<String, Student>> first =
list.stream()
.map(this::makeMapEntry)
.filter(predicate::apply)
.findFirst();
return first.orElse(makeMapEntry(null)).getValue();
}
#Override
public void writeData(ObjectDataOutput out) throws IOException {
out.writeUTF(listName);
out.writeObject(predicate);
}
#Override
public void readData(ObjectDataInput in) throws IOException {
listName = in.readUTF();
predicate = in.readObject();
}
private Map.Entry<String, Student> makeMapEntry(Student student) {
return new QueryEntry(listName, student);
}
}
// Used to query the list entries
private static class QueryEntry
implements Map.Entry<String, Student>,
Extractable {
private final String key;
private final Student value;
private QueryEntry(String key, Student value) {
this.key = key;
this.value = value;
}
#Override
public Object getAttributeValue(String attributeName)
throws QueryException {
if ("number".equals(attributeName)) {
return value.getNumber();
} else if ("name".equals(attributeName)) {
return value.getName();
}
return null;
}
#Override
public AttributeType getAttributeType(String attributeName)
throws QueryException {
return AttributeType.STRING;
}
#Override
public String getKey() {
return key;
}
#Override
public Student getValue() {
return value;
}
#Override
public Student setValue(Student value) {
throw new UnsupportedOperationException();
}
}
}
And finally how to run this code:
List<Student> students = hz.getList(listName);
addStudents(students);
StudentSearch search = new StudentSearch(hz);
Student result = search
.findFirstByNameAndNumber(listName, "Tony", "001");
System.out.println(result);
I hope this helps a bit :)
I can not get what id in the object is for as you need to query id+name (therefore id is not intended to be unique?). Why you store them in a Set if you know you will need to query them (please give more info).
As you pointed out there are not predicates in Set. IMHO this is because entries not associated with a Key can not be indexed. Without possibility to ad an index (Or at leas range-scan on key) the concept of predicates crumble down, as any query will still iterate over the entire set. As far as i can see, you do not have many options:
If you are using set must to have unique entries, don't!
In this case, move it to a map, an use a key as anyone, for example your object id. If there may be id, duplicates, you can make more complex key like id+name or even hash the entire object. Once you have to put a new Object make the key and check if it is already present if so fallback with your custom logic. Map will give you all the Indexes and predicates you can wish for.
From the other hand if for some reasons that are not under your control you Must use set... then you can do it in many ways but I will suggest as follow:
Listen on any modification to the Set (Or if is static or consistency is not a concern scan periodically the set
Build your custom index
How to build the index:
It really depend upon the performances you want, the RAM impact you can accept and how different queries may be. (Let assume that you only queries are always the same eg "name equals to").
MultiMap<String, String> index
// index.put(name, key)
You structure your index by adding, removing entries on each Set modification, using in your MultiMap the object.name as key and actual Key in the Set as value in the multimap. Once you search for a give name you simply do as follow (pseudo-pseudo code)
MultiMap<String, String> index;
Map<String, your_object_class> your_set;
function getByName(String name)
{
List<String> name_key_set index.get( name );
List<your_object_class> out;
for(String key : name_key_set)
out.add(index.get(key));
return out;
}
IMO there is nothing you can call query on a Set ( referring to query as a clever way to retrieve data and not a brute force iteration ) as any such system will require key=>value entries.
With further information we can help you better :)