How to sort using RxAndroid - android

How to sort my list through Rx function, My list contain three type of different source then I want to display my list sorted using date, how to apply that using RxAndroid?
subscriptions.add(complaintsAPI.getComplaintsAPI(userDetails.getUsername())
.compose(ReactiveUtils.applySchedulers())
.map(list -> {
List<ComplaintsRowModel> rowModel = new ArrayList<>();
for (Complaint complaint : list.getComplaints()) {
rowModel.add(new ComplaintsRowModel(complaint.getDisputeNo(),
complaint.getOpenDate(), complaint.getArea(), complaint.getStatus()));
model.complaintsList.put(complaint.getDisputeNo(), complaint);
}
for (OnlineRequest onlineRequest : list.getOnlineRequests()) {
rowModel.add(new ComplaintsRowModel(onlineRequest.getRequestNo(), onlineRequest.getOpenDate(),
onlineRequest.getArea(), onlineRequest.getStatus()));
model.complaintsList.put(onlineRequest.getRequestNo(), onlineRequest);
}
for (LlTickets llTickets : list.getLlTickets()) {
rowModel.add(new ComplaintsRowModel(llTickets.getTicketNo(), llTickets.getOpenDate(),
llTickets.getType(), llTickets.getStatus()));
model.complaintsList.put(llTickets.getTicketNo(), llTickets);
}
return rowModel;}
).toSortedList(){
//how to sort here
}).subscribe(new RequestSubscriber<List<ComplaintsRowModel>>(view.getContext(), view.progressView) {
#Override
public void onFailure(RequestException requestException) {
view.showError(requestException);
}
#Override
public void onNoData() {
super.onNoData();
isAllDataLoaded = true;
view.noDataFound();
model.setNoDataFound(true);
}
#Override
public void onNext(List<ComplaintsRowModel> complaintsRowModels) {
isAllDataLoaded = true;
model.setRowModel(complaintsRowModels);
view.buildList(complaintsRowModels);
}
}));
I think in toSortedList() can I sort my list but I don't know the way to apply that.

The toSortedList operator would only work on Observable<ComplaintRowModel> while what you have is Observable<List<ComplaintRowModel>>. So first you have to transform your observable with
flatMapIterable(complaintRowModels -> complaintRowModels)
to map it to an observable of the list elements. Then you can apply the sorting something like
toSortedList((complaintRowModel, complaintRowModel2) -> {
Date date = complaintRowModel.getDate();
Date date2 = complaintRowModel2.getDate();
// comparing dates is very much dependent on your implementation
if (date <before> date2) {
return -1;
} else if (date <equal> date2) {
return 0;
} else {
return 1;
}
})
Then you get an observable of sorted list.

As per you don't want to provide specific information about your problem, there is generic answer.
When data object which need to be sorted implements Comparable or it's primitive type.
Observable.just(3, 2, 1)
.toSortedList()
.subscribe(list -> System.out.print(Arrays.toString(list.toArray())));
[1, 2, 3]
When data object which need to be sorted doesn't implement Comparable or implements it, but you need to specify how you'd like to sort data.
That sample illustrate how to sort list of objects by val field in descended order.
static class ToSort {
Integer val;
public ToSort(Integer val) {
this.val = val;
}
#Override
public String toString() {
return "ToSort{" +
"val=" + val +
'}';
}
}
public static void main(String[] args) {
Observable.just(new ToSort(1), new ToSort(2), new ToSort(3))
.toSortedList((o1, o2) -> (-1) * o1.val.compareTo(o2.val))
.subscribe(list -> System.out.print(Arrays.toString(list.toArray())));
}
[ToSort{val=3}, ToSort{val=2}, ToSort{val=1}]

Different approach to replce the
// comparing dates is very much dependent on your implementation
if (date <before> date2) {
return -1;
} else if (date <equal> date2) {
return 0;
} else {
return 1;
}
Using a static import java.util.Comparator.comparing;
you can do comparing using method references found inside of your date object.
Ex.
In this instance unsortedDevices is a standard ObservableList to be used in a TablView.
SortedList<HistoryDisplayItem> sortedItems = new SortedList<>(unsortedDevices,
comparingInt(HistoryDisplayItem::getNumber));

Related

Android mediator live data combine 2 live data into one stream and one trigger

I have 2 live data, I add them as sources to a mediator live data, I expose this from a view model for a fragment to observe.
When either of the live data changes it triggers the onChanged method of the mediator live data, which means my observer gets triggered twice, what I want is to combine the two and observe just one stream that only triggers once, is there something I'm missing or do I need to roll my own method for this? currently I do this, which triggers twice
SOME CODE REMOVED FOR BREVITY
public CardViewModel(#NonNull Application application , int clicks, String[] cardArgs){
sentenceRepository = new SentenceRepository(application);
cards = Transformations.switchMap(search, mySearch -> sentenceRepository.searchLiveCardListByWordTypeAndWordDescriptionAndSearchWord(cardArgs[0],cardArgs[1],mySearch));
groupRepository = new GroupRepository(application);
groups = groupRepository.getGroupsByWordDescriptionAndWordType(cardArgs[0],cardArgs[1]);
sentencesAndGroups = new MediatorLiveData<>();
sentencesAndGroups.addSource(cards, sentences -> {
Log.d(TAG,"addSource cards");
sentencesAndGroups.setValue(combineLatest(sentences, groups.getValue()));
});
sentencesAndGroups.addSource(groups, groupsWithSentences -> {
Log.d(TAG,"addSource groups");
sentencesAndGroups.setValue(combineLatest(cards.getValue(), groupsWithSentences));
});
}
private List<Visitable> combineLatest(List<Sentence> sentenceList, List<GroupsWithSentences> groupsWithSentences) {
List<Visitable> visitableList = new ArrayList<>();
if (sentenceList != null){
visitableList.addAll(sentenceList);
}
if (groupsWithSentences != null){
visitableList.addAll(groupsWithSentences);
}
return visitableList;
}
any help?
You can use a BiFunction. In my project I have a class which contains this:
public class MultipleLiveDataTransformation {
#MainThread
public static <X, Y, O> LiveData<O> biMap(LiveData<X> data1, LiveData<Y> data2, final BiFunction<X, Y, O> biFun) {
final MediatorLiveData<O> result = new MediatorLiveData<>();
result.addSource(data1, x -> result.setValue(biFun.apply(x, data2.getValue())));
result.addSource(data2, y -> result.setValue(biFun.apply(data1.getValue(), y)));
return result;
}
}
You can use it like this:
public LiveData<Visitable> getVisitables() {
return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
List<Visitable> visitableList = new ArrayList<>();
if (gro != null) {
visitableList.addAll(gro);
}
if (sen != null) {
visitableList.addAll(sen);
}
return visitableList;
});
}
I do not fully understand what lists you have and what you want to observe. The example I gave here can observe two LiveData objects and triggers when one of them needs to update. It will always give you the most up to date version of the Visitable objects.
If I don't understand the problem, can you explain what LiveData objects need to be combined and what the result needs to be?
In the case, that an extra LiveData object needs to be observed in the MultipleDataTransformation, it is possible to make a triMap.
Edit:
You can try this:
public LiveData<Visitable> getVisitables() {
return MultipleLiveDataTransformation.biMap(groups, sentences, (gro, sen) -> {
List<Visitable> visitableList = new ArrayList<>();
if (gro != null && !gro.isEmpty() && sen != null && !sen.isEmpty()) {
visitableList.addAll(gro);
visitableList.addAll(sen);
}
return visitableList;
});
}

Ormlite ForeignCollection with Gson

Been struggling with this all day. I feel like I am one annotation away from the right solution.
I am getting an JSON from an API, and parsing it using Gson inside Volley request into a object.
Then I want to store the object in DB, using ORMLite.
The problem is that my JSON has lists of other objects. So I have decided that ForeignCollection are required.
Here is simplified version of what I am getting as JSON:
{
"b": [
{"title"="abc","id="24sfs"},
{"title"="def", "id="532df"}
],
"c": [
{"description"="abc","id="34325"},
{"description"="def", "id="34321"}
],
"id"="ejsa"
}
Lets call this whole object class A. The objects inside "b", are B, inside "c", class C.
B and C are the similar. This leads to the following class definitions:
class A {
#DatabaseField(index = true, unique = true, id = true)
private String id;
#ForeignCollectionField(eager = true)
public Collection<B> bCollection;
public ArrayList<B> b;
#ForeignCollectionField(eager = true)
public Collection<C> cCollection;
public ArrayList<C> c;
}
class B {
#DatabaseField(foreign=true)
public A a;
#DatabaseField(id = true, index = true, unique = true)
public String id;
#DatabaseField
public String title;
}
The reason we need the ArrayList b and c, is so that gson can parse it correctly. So once I have class A in memory, here is what I do to store it
private void storeA(A a) {
if (a.b != null) {
getHelper().getDao(B.class).callBatchTasks(new Callable<Void>() {
#Override
public Void call() throws Exception {
for (B b : a.b) {
b.a = a;
try {
getHelper().getDao(B.class).createOrUpdate(b);
} catch (Exception e) {
}
}
return null;
}
});
}
/*
Here we start running into problems. I need to move the data from the ArrayList to the Collection
*/
a.bCollection = a.b; // but this seems to work, since bCollection is a Collection
a.cCollection = a.c;
getHelper().getDao(A.class).createOrUpdate(a);
}
So it seems to store correctly, no errors as far as I can tell. But when I try to retrieve as follows, I can't retrieve anything out of bCollection:
private void load() {
try {
List<A> as = getHelper().getDao(A.class).queryForEq("id", "ejsa");
if (as != null && as.size() > 0) {
A a = as.get(0);
CloseableWrappedIterable<B> cwi = a.bCollection.getWrappedIterable();
try {
for (B b : cwi) {
Log.e(b.title);
}
} finally {
cwi.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
What am I doing wrong? Do I need to specify foreignColumnName for some of these things? I can't tell if the things are not being stored correctly or if I am just failing to retrieve them correctly?
I would try removing the following two lines:
a.bCollection = a.b;
a.cCollection = a.c;
A's ForeignCollection's should be auto-magically populated for you by ORMLite when you query for A, you do not need to set them yourself.

How to remove duplicates from ArrayList of type Object? [duplicate]

This question already has answers here:
How to remove duplicates from a list?
(15 answers)
Closed 8 years ago.
I want to remove duplicates from ArrayList of type Alerts where Alerts is a class.
Class Alerts -
public class Alerts implements Parcelable {
String date = null;
String alertType = null;
String discription = null;
public Alerts() {
}
public Alerts(String date, String alertType, String discription) {
super();
this.date = date;
this.alertType = alertType;
this.discription = discription;
}
}
Here is how I added the elements -
ArrayList<Alerts> alert = new ArrayList<Alerts>();
Alerts obAlerts = new Alerts();
obAlerts = new Alerts();
obAlerts.date = Date1.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
obAlerts = new Alerts();
obAlerts.date = Date2.toString();
obAlerts.alertType = "Alert Type 1";
obAlerts.discription = "Some Text";
alert.add(obAlerts);
What I want to remove from them-
I want all alerts which have unique obAlerts.date and obAlerts.alertType. In other words, remove duplicate obAlerts.date and obAlerts.alertType alerts.
I tried this -
Alerts temp1, temp2;
String macTemp1, macTemp2, macDate1, macDate2;
for(int i=0;i<alert.size();i++)
{
temp1 = alert.get(i);
macTemp1=temp1.alertType.trim();
macDate1 = temp1.date.trim();
for(int j=i+1;j<alert.size();j++)
{
temp2 = alert.get(j);
macTemp2=temp2.alertType.trim();
macDate2 = temp2.date.trim();
if (macTemp2.equals(macTemp1) && macDate1.equals(macDate2))
{
alert.remove(temp2);
}
}
}
I also tried-
HashSet<Alerts> hs = new HashSet<Alerts>();
hs.addAll(obAlerts);
obAlerts.clear();
obAlerts.addAll(hs);
You need to specify yourself how the class decides equality by overriding a pair of methods:
public class Alert {
String date;
String alertType;
#Override
public boolean equals(Object o) {
if (this == 0) {
return true;
}
if ((o == null) || (!(o instanceof Alert)))
return false;
}
Alert alert = (Alert) o;
return this.date.equals(alert.date)
&& this.alertType.equals(alert.alertType);
}
#Override
public int hashCode() {
int dateHash;
int typeHash;
if (date == null) {
dateHash = super.hashCode();
} else {
dateHash = this.date.hashCode();
}
if (alertType == null) {
typeHash = super.hashCode();
} else {
typeHash = this.alertType.hashCode();
}
return dateHash + typeHash;
}
}
You can then loop through your ArrayList and add elements if they aren't already there as Collections.contains() makes use of these methods.
public List<Alert> getUniqueList(List<Alert> alertList) {
List<Alert> uniqueAlerts = new ArrayList<Alert>();
for (Alert alert : alertList) {
if (!uniqueAlerts.contains(alert)) {
uniqueAlerts.add(alert);
}
}
return uniqueAlerts;
}
However, after saying all that, you may want to revisit your design to use a Set or one of its family that doesn't allow duplicate elements. Depends on your project. Here's a comparison of Collections types
You could use a Set<>. By nature, Sets do no include duplicates. You just need to make sure that you have a proper hashCode() and equals() methods.
In your Alerts class, override the hashCode and equals methods to be dependent on the values of the fields you want to be primary keys. Afterwards, you can use a HashSet to store already seen instances while iterating over the ArrayList. When you find an instance which is not in the HashSet, add it to the HashSet, else remove it from the ArrayList. To make your life easier, you could switch to a HashSet altogether and be done with duplicates per se.
Beware that for overriding hashCode and equals, some constraints apply.
This thread has some helpful pointers on how to write good hashCode functions. An important lesson is that simply adding together all dependent fields' hashcodes is not sufficient because then swapping values between fields will lead to identical hashCodes which might not be desirable (compare swapping first name and last name). Instead, some sort of shifting-operation is usually done before adding the next atomic hash, eg. multiplying with a prime.
First store your datas in array then split at as one by one string,, till the length of that data execute arry and compare with acyual data by if condition and retun it,,
HashSet<String> hs = new HashSet<String>();
for(int i=0;i<alert.size();i++)
{
hs.add(alert.get(i).date + ","+ alert.get(i).alertType;
}
alert.clear();
String alertAll[] = null;
for (String s : hs) {
alertAll = s.split(",");
obAlerts = new Alerts();
obAlerts.date = alertAll[0];
obAlerts.alertType = alertAll[1];
alert.add(obAlerts);
}

sort list by date in android from json not from db

hi i am sorting the date from the webservices ie json and i need to sort that based on the created date.normal sort Collections.sort is not working i need to format the date before sort how to do that
CommunicationEngine.post(getApplicationContext(), "sports",
mylibraryRequest, new AsyncHttpResponseHandler() {
com.loopj.android.http.AsyncHttpResponseHandler#onStart()
com.loopj.android.http.AsyncHttpResponseHandler#onSuccess(java.lang.String)
#Override
ObjectMapper sportsMapper = new ObjectMapper();## Heading ##try {
SportsResponse sportsResponse = sportsMapper.readValue(sportsResponseASString,SportsResponse.class);
if (null != sportsResponse) {
List<Assets> assets = sportsResponse.getAssets();
(Assets asset : assets) {
//sort list
sort_sportList.add(asset.getTitle()
.trim());
if(asset.getSportType() != null){
sort_sport.add(asset.getSportType().trim()); } EGLibContent eglibitem = new EGLibContent(
.getAssetEventDate(),
adapter.getKey("Contents");
adapter.addeglibcontent(eglibitem,ListView);
i use title normally by sorting collections.sort()
i want to sort getAssetEventDate(). the value returned from tthis function
So you want to sort the List using getAssetEventDate()?
getAssetEventDate returns a number?
Collection.sort(assets, new Comparator<Asset>() {
#Override
public int compare(Asset lhs, Asset rhs) {
if (lhs.getAssetEventDate() < rhs.getAssetEventDate() {
return -1;
} else if (lhs.getAssetEventDate() > rhs.getAssetEventDate() {
return 1;
} else {
return 0;
}
}
}

How to sort arrayList alphabetically with numbers in last in android?

I have an ArrayList and I would like to sort the contents so that anything with English alphabets are sorted first and then anything with numbers and non English characters are sorted last.
For example: A, B , C ... Z, 1 , 2, 3 ... 9, _test1,_2, ...
Currently I only know how to sort items in alphabetical order. Suggestions?
class Comparator implements Comparator<Name> {
#Override
public int compare(Name name1, Name name2) {
return name1.getName().toLowerCase().compareTo(name2.getName().toLowerCase());
}
}
You can use the following implementation of Comparator:
Comparator<String> comparator = new Comparator<String>() {
#Override
public int compare(String lhs, String rhs) {
boolean lhsStartsWithLetter = Character.isLetter(lhs.charAt(0));
boolean rhsStartsWithLetter = Character.isLetter(rhs.charAt(0));
if ((lhsStartsWithLetter && rhsStartsWithLetter) || (!lhsStartsWithLetter && !rhsStartsWithLetter)) {
// they both start with letters or not-a-letters
return lhs.compareTo(lhs);
} else if (lhsStartsWithLetter) {
// the first string starts with letter and the second one is not
return -1;
} else {
// the second string starts with letter and the first one is not
return 1;
}
}
};

Categories

Resources