Sort by condition input with ArrayList Android - android

I have a arraylist with two field Name and Year. I want to sort this array with condition input name (sort by name input). If the name is same it will sort by year.
Example
Name Year
Ann 2000
Bech 2001
Bach 2013
Bach 2012
Chu 1999
Assume that I create a function is sort with input is Bach. The result will display
Name Year
Bach 2013
Bach 2012
Ann 2000
Bech 2001
Chu 1999
Because with input is Bach and the first I want to display all name with "Bach" If the same name I will sort it by year(largest-smallest). If don't same "Bach" name I will sort by A-Z using compareTo()
This is my code but I don't have input condition name . Please make a new function help me same sort_inputname(String inputname)
//Class compare Name- Year
public class Search_Name_Year_Comparator implements Comparator<SearchListInformation>
{
public int compare(SearchListInformation left,
SearchListInformation right) {
// TODO Auto-generated method stub
int dateComparison;
int dataComparison = 0;
if(left.getName().compareTo(right.getName())==0)
{
if(left.getYear().compareTo(right.getYear())>0)
{
return -1;
}
else if(left.getYear().compareTo(right.getYear())<0)
{
return 1;
}
else
return 0;
}
else
return left.getName().compareTo(right.getName());

It is a little bit hard to understand your question (I assume you are not a native English speaker, but you can't be blamed for that). From what I understand, you want to sort an ArrayList of objects that have 2 properties : Name and Year. Let's just assume those objects are called "SearchListInformation", so you're trying to sort an ArrayList of SearchListInformation.
What I would do here is make the SearchListInformationclass implement the Comparable (not Comparator) interface (see the link for more information).
Then you can juste use Collections.sort to sort your ArrayList, for instance :
ArrayList<SearchListInformation> list = new ArrayList<SearchListInformation>();
list.add(new Person("Bob", 2000));
list.add(new Person("Lucy", 2010));
Collections.sort(list);
If you want to use the Comparator interface, you can also use Collections.sort(List, Comparator). Then you can use the code you posted, but I would simplify it this way :
#Override
public int compare(SearchListInformation left, SearchListInformation right) {
if(left.getName().compareTo(right.getName())==0)
return -1*left.getYear().compareTo(right.getYear())
else
return left.getName().compareTo(right.getName());
}
Edit : If you want to be able to specify a name that should be always at the beginning of the list, you should use the second option : implement the Comparator interface like this :
public MyComparator implements Comparator<SearchListInformation> {
protected String _priorityName;
public MyComparator(String priorityName) {
_priorityName = priorityName;
}
#Override
public int compare(SearchListInformation left, SearchListInformation right) {
if(left.getName().compareTo(right.getName())==0)
return -1*left.getYear().compareTo(right.getYear())
else if(left.getName().equals(_priorityName)
return -1;
else if(right.getName().equals(_priorityName)
return 1;
else
return left.getName().compareTo(right.getName());
}
}
Then you can use :
Collections.sort(list, new MyComparator("Bach"));

Related

Unable to sort the data with Comparator in android

I'm trying to make a code to sort the data for my list in the following order and know that I have to use a Comparator, however I have no clue how to implement the following logic into the comparator. Some help or examples will be great ! I would love to hear from you.
final private ArrayList<BookItem> books = new ArrayList<>();
Collections.sort(books, compareBooks);
The way I want the list to be sorted as follows
Display order
The lower the sort_order number, the item will be shown The newer
the date of the start_date is, the higher the item will be shown
The bigger the ID value, the item will be
private Comparator<BookItem> compareBooks = (o1, o2) -> {
if (o1.sort_order == BookItem.ORDER && o2.sort_order != BookItem.ORDER) {
return -1;
} else if (o1.start_date != BookItem.START && o2.start_date == BookItem.START) {
return 1;
} else if (o1.ID == BookItem.ID && o2.ID == BookItem.ID) {
return 0
}
};
I would do it step by step as in your list of sort attributes
The lower the sort_order number, the item will be shown The newer
the date of the start_date is, the higher the item will be shown
The bigger the ID value, the item will be
a
private Comparator<BookItem> compareBooks = (o1, o2) -> {
int result =o1.sort_order - o2.sort_order
if(0==result){
result=o1.start_date.compareTo(o2.start_date);
}
if(0==result){
result=o1.ID-o2.ID;
}
};
Most likely I messed up the order of at least one of your attributes, but the idea should be clear.

Most efficient way of comparing long arrays of strings

I'm using the speech recognizer to get a voice input from the user, it returns an array of 5 strings which I pass to this method
public int analyzeTag(ArrayList<String> voiceResults,Editor editor, Context context){
for (String match : voiceResults) {
Log.d(TAG, match);
if (match.equalsIgnoreCase(context.getResources().getString(R.string.first_tag))){
editor.append(context.getResources().getString(R.string.first_tag));
return 1;
}
else if (match.equalsIgnoreCase(context.getResources().getString(R.string.second_tag))){
editor.append(context.getResources().getString(R.string.second_tag));
return 1;
}
//etc....(huge list of tags)
//Some tags might also have acceptable variations, example:
else if (match.equalsIgnoreCase("img") || match.equalsIgnoreCase("image")
{
editor.append("img"); //the string to append is always taken from the first variation
}
}
return 0;
}
This method compares the results with a list of tags, the tag list will be pretty big with hundreds of tags so I would like to find the most efficient way to do this operation.
I need help with:
1.Is my way of comparing results the most efficient? Is there a better way? (from the user experience perspective, I don't want users waiting a long time to get a result).
The voice input will be a big part of my app so this method will be called quite often
2.I have a long list of tags, obviously the if(), elseIf() route is gonna be quite repetitive, is there a way to iterate this? Considering the fact that some tags might have variations (even more than 1)and that the variation 1 ("img") will be the same for everyone, but other variations will be locale/language sensitive example: "image" for english users "immagini" for italian users etc.
Text appended to the editor will be always taken from the first variation
How about puting tags in a StringArray and then iterate though the array ?
String[] tags = context.getResources().getStringArray(R.array.tags);
for (String match : voiceResults) {
for (int index = 0; index < tags.length; index++ ) {
if (match.equalsIgnoreCase(tags[index]) {
editor.append(tags[index]);
}
}
}
Here's the doc on StringArray

How to make .contains search for every string in an array?

I have this code :
String[] whereyoufromarray = {"where", "you", "from"};
for (String whereyoufromstring : whereyoufromarray)
{
if (value.contains(whereyoufromstring)) {
//statement
}
}
But I want that if to only execute the statement if "value" has all of the words included in the array, something like "where are you from?". Currently if value has ONLY one of the words in the array the statement is executed.
I can do this with if (value.contains("where") && value.contains("you") && value.contains ("from")) but this just seems unnecessarily long. There has to be a workaround using arrays that I am missing.
Well, what is it?
p.s.: sorry for poor grammar. i'm suffering from sleep deprivation.
String[] whereyoufromarray = {"where", "you", "from"};
boolean valueContainsAllWordsInArray = true;
for (String whereyoufromstring : whereyoufromarray) {
// If one word wasn't found, the search is over, break the loop
if(!valueContainsAllWordsInArray) break;
valueContainsAllWordsInArray = valueContainsAllWordsInArray &&
value.contains(whereyoufromstring);
}
// valueContainsAllWordsInArray is now assigned to true only if value contains
// ALL strings in the array
For a case like this, I typically implement a function just to make the test. Let's call it containsAll()
public static boolean containsAll(String[] strings, String test)
{
for (String str : strings)
if (!test.contains(str))
return false;
return true;
}
And now you just do
if (containsAll(whereyoufromarray, value))
//statement
String[] whereyoufromarray = {"where", "you", "from"};
int arrayLength = whereyoufromarray.length;
int itemCount = 0;
for(String whereyoufromstring : whereyoufromarray)
{
if(value.contains(whereyoufromstring))
{
itemCount++;
}
}
if (itemCount == arrayLength){
//do your thing here
}
rough idea. I don't have my IDE up to proof this, but basically you can set a counter to = the length of your known array, then check each value in the array to see if it contains a match..if it does, increment another counter. At the end, test your counter to see if it matches the length of your array, so in your example, if itemCount= 3, then all values matched. if it was 2, then one would be missing and your method wouldn't execute.

Sort by Phone Number

I used the following code snippet to sort by phone number:
class Item { String addr; /* phone number */ }
private int compareByAddr(Item objA, Item objB) {
if (objA.addr==null && objB.addr==null) {
return 0;
} else if (objA.addr==null && objB.addr!=null) {
return -1;
} else if (objA.addr!=null && objB.addr==null) {
return 1;
} else {
if (PhoneNumberUtils.compare(objA.addr, objB.addr)) {
return 0;
} // end if
return objA.addr.compareTo(objB.addr);
} // end if
} // end compareByAddr()
However I got an Exception:
E/AndroidRuntime(12157): java.lang.IllegalArgumentException:
Comparison method violates its general contract!
I've searched about it, and found out that it means my sorting algorithm is not transitive...
Does anyone has a better algorithm for sorting by phone number?
Problem is you have 2 String's which represent phone numbers and you want to compare them and sort them from big to small like there were numbers...
but comparing 2 String to each-other (like in your code snippet):
objA.addr.compareTo(objB.addr);
wont work :(
you can do this by manipulating the String to a number (and discarding all non digit from it)
and then compare the 2 like they were regular numbers ...
String phone1Str
String phone2Str
int phone1
int phone2
phone1Str= phone1Str.replaceAll("\\D+",""); //using reg-ex to get only digits
phone1= Integer.valueOf(phone1Str); //convert to int to compare numbers
phone2Str= phone2Str.replaceAll("\\D+","");
phone2= Integer.valueOf(phone2Str);
if (PhoneNumberUtils.compare(phone1Str,phone2Str)
//they are equal
else if (phone1>phone2)
//phone1 is the larger number !
else
//phone2 is the larger number !
hope this helps

string.compareTo(string) not yielding correct results on sort

I have a list view with place distances, as shown below:
100
200
300
400
500
50
600
70
40
i need to sort this place distances in both ascending and descending order. So wat i did was, sorting the adapter and use adapter.notifyDataSetChanged(). Everything works fine if the distances are 3 digit numbers ie., 230, 450, 352, 254 and so on. But if the place distance is 2 digit like 52, 65, 75 etc, i am getting wrong sorted values as shown below.
for ascending order : after sort i am getting this order
100
200
300
400
500
600
50
60
70
for descending order : after sort i am getting this order
70
60
50
600
500
400
300
200
100
my code for sorting is shown below:
case R.id.action_sort_dist_fn:
adapter.sort(new Comparator<Place>() {
#Override
public int compare(Place lhs, Place rhs) {
return rhs.getPlaceDistance().compareTo(
lhs.getPlaceDistance());
};
});
adapter.notifyDataSetChanged();
break;
case R.id.action_sort_dist_nf:
adapter.sort(new Comparator<Place>() {
#Override
public int compare(Place lhs, Place rhs) {
return lhs.getPlaceDistance().compareTo(
rhs.getPlaceDistance());
};
});
Place.java
public class Place {
String placeName = "";
String placeDistance="";
String placeCategoryIcon;
public Place(String placeName, String placeDistance,
String placeCategoryIcon) {
this.placeName = placeName;
this.placeDistance = placeDistance;
this.placeCategoryIcon = placeCategoryIcon;
}
public String getPlaceName() {
return placeName;
}
public void setPlaceName(String placeName) {
this.placeName = placeName;
}
public String getPlaceDistance() {
return placeDistance;
}
public void setPlaceDistance(String placeDistance) {
this.placeDistance = placeDistance;
}
public String getPlaceCategoryIcon() {
return placeCategoryIcon;
}
public void setPlaceCategoryIcon(String placeCategoryIcon) {
this.placeCategoryIcon = placeCategoryIcon;
}
}
First of all the sorting you give is not the actual one you are getting. E.g the second one is actually:
70
600
60
500
50
400
300
200
100
The comparison shouldn't be done using strings - it compares lexicographically, which means that the comparison is as described here. So "abc" is greater than "ab" and "d" is greater than "ccc".
You want to compare the number values, so please do so. One option is to use Integer.valueOf to get the actual integer value equivalents of the values you use.
By the way I see no gain for you to have placeDistance a String field. Why don't you have it as Integer all along?
You're sorting Strings. The natural ordering for String is the lexicographical ordering. What you want is integer ordering. So use an int rather than a String for Place.placeDistance. Or at least transform the strings to compare to integers, and compare those integers.
Also, calling your field placeDistance adds unnecessary noise. Just call it distance (and do the same for the other fields, of course).
The problem is that in your comparator you use:
return rhs.getPlaceDistance().compareTo(lhs.getPlaceDistance());
and placeDistance is a string, therefore you are comparing Strings, not numeric values.
I think it is because you are comparing strings. try changing your compare override to:
#Override
public int compare(Place lhs, Place rhs)
{
return Integer.parseInt(rhs.getPlaceDistance()).compareTo(
Integer.parseInt(lhs.getPlaceDistance()));
};
I think the ideal solution might be to hold integers in your place rather than Strings.
Note that if you will have decimal places you should try Float or Double instead of Integer

Categories

Resources