Sort ArrayList by search keyword - android

I have an ArrayList with This values
"Babel"
"Isabelle"
"Elon"
"Eloise"
I'm typing "el" on the search, I sort the list and I would like to have this result
"Eloise"
"Elon"
"Babel"
"Isabelle"
Because "Eloise" start with my search "el" like "Elon" and then "Babel" because alphabetically is before "Isabelle"
I don't know how to sort by the firsts chars of the array I try to substring names
users.sort((o1, o2) -> {
String name1 = o1.getNickname();
String name2 = o2.getNickname();
if (o1.getNickname().length() >= finalS.length()) {
name1 = o1.getNickname().substring(0, finalS.length());
}
if (o2.getNickname().length() >= finalS.length()) {
name2 = o2.getNickname().substring(0, finalS.length());
}
return name1.compareTo(name2);
});
But this return name1.compareTo(name2); compare the cutted String and order alphabetical.
I try to add this below the substring
if (name1.contains(finalS)) return 1;
or
if (name2.contains(finalS)) return 1;
nothing work Babel is always at the first position

In most cases, the factory methods in the Comparator interface are suitable and allow to reduce the redundancy of applying operations to both arguments of the comparator.
Since your input is "el" but the names start with an uppercase letter, you want a case insensitive partial matching, followed by sorting by the strings’ natural order.
List<String> users = Arrays.asList("Babel", "Isabelle", "Elon", "Eloise");
String finalS = "el";
users.sort(Comparator.comparing(
(String u) -> !finalS.regionMatches(true, 0, u, 0, finalS.length()))
.thenComparing(Comparator.naturalOrder()));
users.forEach(System.out::println);
Eloise
Elon
Babel
Isabelle
Since apparently there’s a class User whose Nickname property you want to compare, the complete sorting code would look like
users.sort(Comparator.comparing(User::getNickname, Comparator.comparing(
(String u) -> !finalS.regionMatches(true, 0, u, 0, finalS.length()))
.thenComparing(Comparator.naturalOrder())));

Your Comparator should look kind of like this:
Sorts those which start with your search first, then those which only contain them. But the best way for searching would be to use diff-match-patch (https://github.com/google/diff-match-patch).
public int compare(User o1, User o2) {
String search = YOUR_SEARCH.toLowerCase();
String name1 = o1.getNickname().toLowerCase();
String name2 = o2.getNickname().toLowerCase();
int i = Boolean.compare(name2.startsWith(search), name1.startsWith(search));
if (i != 0)
return i;
i = Boolean.compare(name2.contains(search), name1.contains(search));
if (i != 0)
return i;
return name2.compareTo(name1);
}

Related

How can I sort an ArrayList<HashMap<Integer, Boolean>>?

In my MainActivity.java I have:
public static ArrayList<HashMap<Integer,Boolean>> booleanArrayList = new ArrayList<>();
public static void setBooleanArrayList(int p, Boolean b){
HashMap<Integer,Boolean> map = new HashMap<>();
map.put(p, b);
booleanArrayList.add(map);
}
public static HashMap<Integer, Boolean> getBooleanArrayList(int position){
return booleanArrayList.get(position);
}
I have a fragment which has a button. When the button is clicked I want it to sort MainActivity.booleanArrayList in ascending order.
For example:
{1,true}
{4,true}
{2,false}
{3,true}
sorted:
{1=true}
{2=false}
{3=true}
{4=true}
How would I go about sorting the ArrayList> once it is populated?
There are 2 steps in doing that. First, write a Comparator that will compare 2 Maps:
public class MapKeyComparator implements Comparator<Map<Integer, Boolean>> {
#Override
public int compare(Map<Integer, Boolean> me, Map<Integer, Boolean> him) {
Set<Integer> meSet = me.keySet();
Set<Integer> himSet = him.keySet();
// Sanity check
if(me.size() != 1 || himSet.size() != 1){
throw new RuntimeException("Comparison can only be done between 2 valid integers.");
}
// Values
int meI = 0, himI = 0;
for(Integer i : meSet){
meI = i;
}
for(Integer i : himSet){
himI = i;
}
// Compare
if(meI > himI){
return -1;
}
else if(meI < himI){
return 1;
}
else{
return 0;
}
}
}
And then, sort the list like below:
Collections.sort(booleanArrayList, new MapKeyComparator());
Explanation:
Well, a Comparator is an interface that you can implement to compare 2 objects, say Integers. It can be any object in general but think about it, since it is comparison, it should make sense too comparing them. For ex, you wouldn't compare Bird object with a Tree. You can compare one Bird type with that of another because they have attributes that you can compare.
Now, in your case, we had to compare the Keys of the Maps present in the ArrayList. That means, the object to compare is a Map but based on what?
Well, you already know that - the Key of the Map. And, Comparator is an interface that facilitates just that.
So, we shall build a Comparator for comparing 2 Maps based on each Map's key. This Comparator in turn shall be used by the Collections.sort() method which takes a list of objects to compare and a Comparator to compare them.
Before we build the Comparator, lets see what the Docs have to say about a Comparator.
public interface Comparator<T>
A comparison function, which imposes a total ordering on some
collection of objects. Comparators can be passed to a sort method
(such as Collections.sort or Arrays.sort) to allow precise control
over the sort order. Comparators can also be used to control the order
of certain data structures (such as sorted sets or sorted maps), or to
provide an ordering for collections of objects that don't have a
natural ordering.
And about the method you have to implement,
int compare(T o1, T o2)
Parameters:
o1 - the first object to be compared.
o2 - the second object to be compared.
Returns:
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
Notice that it says to return 1 if first object is greater than second. But I did the reverse in the implementation so that you can get a ascending arrangement instead of a descending one in Collections.sort().
The implementation:
The implementation itself it pretty straightforward. Since I have to compare the keys from the Maps, I retrieve the keys in a Set:
Set<Integer> meSet = me.keySet();
Set<Integer> himSet = him.keySet();
Next, I check if they have a single element so that the comparison actually makes sense:
// Sanity check
if (me.size() != 1 && himSet.size() != 1) {
throw new RuntimeException("Comparison can only be done between 2 valid integers.");
}
Next, I iterate the sets to get the one element present in both of them:
// Values
int meI = 0, himI = 0;
for (Integer i: meSet) {
meI = i;
}
for (Integer i: himSet) {
himI = i;
}
Next, we actually compare them,
// Compare
if (meI > himI) {
return -1;
} else if (meI < himI) {
return 1;
} else {
return 0;
}
Also, see the docs for Collections.sort() method.
Having said all that, there are other(better) things you can do for your basic problem like using a TreeMap which arranges the elements when you insert with the natural ordering. So when you retrieve them, you get them in the order you had always wanted. #ravi-koradia 's advice is spot on in terms of that and this article does a great job of explaining it:
https://dzone.com/articles/hashmap-vs-treemap-vs
Instead of Map, you can use your own custom class with position and selected value field, as I can see you need hold only these two value and every map of your list is having single value only.
public static ArrayList<Values> booleanArrayList = new ArrayList<>();
public class Values implements Comparable<Values>{
int position;
boolean isSelected;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Values values = (Values) o;
return position == values.position;
}
#Override
public int hashCode() {
return position;
}
#Override
public int compareTo(#NonNull Values o) {
return (position < o.position) ? -1 : ((position == o.position) ? 0 : 1);
}
}
After that, you can call from anywhere to sort the arraylist:-
Collections.sort(booleanArrayList);

How to get the Index of an element from an array using Arrays.asList

I got an arrray like this in android the usage of Arrays.asList is different because i made the Array with different class "Person":
people = new Person[]{
new Person("Python"),
new Person("PHP"),
new Person("Pascol"),
new Person("PyCrust"),
new Person("C"),
new Person("C#"),
new Person("C++")
};
and i used Arrays.asList in this way
int index= Arrays.asList(people).indexOf("Pascol");
String tags = Integer.toString(index);
Toast.makeText(getApplication(),tags,Toast.LENGTH_SHORT).show();
But i get the value "-1"in the toast.
i could not find the fault.
The problem is that you have a list of Person objects. When you call .indexOf("Pascol"); you pass in a String. Comparing a Person with a String will return always false.Do this instead
int index = -1;
for (int i = 0; i < people.length; i++) {
if (people[i].getName().equals("Pascol")) {
index = i;
}
}
String tags = Integer.toString(index);
Toast.makeText(getApplication(),tags,Toast.LENGTH_SHORT).show();
int index = Arrays.asList(people).indexOf("Pascol");
Pascol is a String here but objects in your array are Person type objects. So indexOf method can not match a String with a Person. You need to override equals() and hashcode() and pass a Person type parameter to the indexOf which name is Pascol. Of course I assume that equality of your object depends on only name attribute.
You should implement Comparable<> in Person class

How to get specific word in a whole string?

I am creating and android app that randomly generates any category, I would like to get the given random category word. This is the example string
String="The category Animals that starts with a letter J";
or
String="The category Colors that starts with a letter V";
I need to get the word Animals or Colors every random String is generated
A not so advanced solution, but easy to understand:
public void findCategory() {
String string = "The category Colors that starts with a letter V";
String[] split = string.split(" ");
int i;
for (i = 0; i < split.length; i++) {
if ("category".equals(split[i])) {
break;
}
}
System.out.println(split[i + 1]);
}
You may use regex.
Matcher m = Pattern.compile("\\bcategory\\s+(\\S+)").matcher(str);
while(m.find()) {
System.out.println(m.group(1));
}
OR
Matcher m = Pattern.compile("(?<=\\bcategory\\s)\\S+").matcher(str);
while(m.find()) {
System.out.println(m.group());
}
Please use Matcher and Pattern -
String input = "The category Animals that starts with a letter J";
Matcher m1 = Pattern.compile("^The category (.*) that starts with a letter (.*)$").matcher(input);
if(m1.find()) {
String _thirdWord = m1.group(1); // Animals
String _lastWord = m1.group(2); // J
System.out.println("Third word : "+_thirdWord);
System.out.println("Last Word : "+_lastWord);
}
Use this, it might fix your issue
String string = "The category Colors that starts with a letter V";
String[] ar = string.split(" ");
System.out.println(ar[2]);

How to split a string and get a specific string in android?

I want to split a string and get a word finally. My data in database is as follows.
Mohandas Karamchand Gandhi (1869-1948), also known as Mahatma Gandhi, was born in Porbandar in the present day state of Gujarat in India on October 2, 1869.
He was raised in a very conservative family that had affiliations with the ruling family of Kathiawad. He was educated in law at University College, London.
src="/Leaders/gandhi.png"
From the above paragraph I want get the image name "gandhi". I am getting the index of "src=". But now how can I get the image name i.e "gandhi" finally.
My Code:
int index1;
public static String htmldata = "src=";
if(paragraph.contains("src="))
{
index1 = paragraph.indexOf(htmldata);
System.out.println("index1 val"+index1);
}
else
System.out.println("not found");
You can use the StringTokenizer class (from java.util package ):
StringTokenizer tokens = new StringTokenizer(CurrentString, ":");
String first = tokens.nextToken();// this will contain one word
String second = tokens.nextToken();// this will contain rhe other words
// in the case above I assumed the string has always that syntax (foo: bar)
// but you may want to check if there are tokens or not using the hasMoreTokens method
Try this code. Check if it working for you..
public String getString(String input)
{
Pattern pt = Pattern.compile("src=.*/(.*)\\..*");
Matcher mt = pt.matcher(input);
if(mt.find())
{
return mt.group(1);
}
return null;
}
Update:
Change for multiple item -
public ArrayList<String> getString(String input)
{
ArrayList<String> ret = new ArrayList<String>();
Pattern pt = Pattern.compile("src=.*/(.*)\\..*");
Matcher mt = pt.matcher(input);
while(mt.find())
{
ret.add(mt.group(1));
}
return ret;
}
Now you'll get an arraylist with all the name. If there is no name then you'll get an empty arraylist (size 0). Always make a check for size.

Extract substring from a string

what is the best way to extract a substring from a string in android?
If you know the Start and End index, you can use
String substr=mysourcestring.substring(startIndex,endIndex);
If you want to get substring from specific index till end you can use :
String substr=mysourcestring.substring(startIndex);
If you want to get substring from specific character till end you can use :
String substr=mysourcestring.substring(mysourcestring.indexOf("characterValue"));
If you want to get substring from after a specific character, add that number to .indexOf(char):
String substr=mysourcestring.substring(mysourcestring.indexOf("characterValue") + 1);
substring():
str.substring(startIndex, endIndex);
Here is a real world example:
String hallostring = "hallo";
String asubstring = hallostring.substring(0, 1);
In the example asubstring would return: h
There is another way , if you want to get sub string before and after a character
String s ="123dance456";
String[] split = s.split("dance");
String firstSubString = split[0];
String secondSubString = split[1];
check this post-
how to find before and after sub-string in a string
substring(int startIndex, int endIndex)
If you don't specify endIndex, the method will return all the
characters from startIndex.
startIndex : starting index is inclusive
endIndex : ending index is exclusive
Example:
String str = "abcdefgh"
str.substring(0, 4) => abcd
str.substring(4, 6) => ef
str.substring(6) => gh
you can use this code
public static String getSubString(String mainString, String lastString, String startString) {
String endString = "";
int endIndex = mainString.indexOf(lastString);
int startIndex = mainString.indexOf(startString);
Log.d("message", "" + mainString.substring(startIndex, endIndex));
endString = mainString.substring(startIndex, endIndex);
return endString;
}
in this mainString is a Super string.like
"I_AmANDROID.Devloper"
and lastString is a string like"." and startString is like"_".
so this function returns "AmANDROID".
enjoy your code time.:)
use text untold class from android: TextUtils.substring (charsequence source, int start, int end)
You can use subSequence , it's same as substr in C
Str.subSequence(int Start , int End)
When finding multiple occurrences of a substring matching a pattern
String input_string = "foo/adsfasdf/adf/bar/erqwer/";
String regex = "(foo/|bar/)"; // Matches 'foo/' and 'bar/'
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input_string);
while(matcher.find()) {
String str_matched = input_string.substring(matcher.start(), matcher.end());
// Do something with a match found
}
The best way to get substring in Android is using (as #user2503849 said) TextUtlis.substring(CharSequence, int, int) method. I can explain why. If you will take a look at the String.substring(int, int) method from android.jar (newest API 22), you will see:
public String substring(int start) {
if (start == 0) {
return this;
}
if (start >= 0 && start <= count) {
return new String(offset + start, count - start, value);
}
throw indexAndLength(start);
}
Ok, than... How do you think the private constructor String(int, int, char[]) looks like?
String(int offset, int charCount, char[] chars) {
this.value = chars;
this.offset = offset;
this.count = charCount;
}
As we can see it keeps reference to the "old" value char[] array. So, the GC can not free it.
In the newest Java it was fixed:
String(int offset, int charCount, char[] chars) {
this.value = Arrays.copyOfRange(chars, offset, offset + charCount);
this.offset = offset;
this.count = charCount;
}
Arrays.copyOfRange(...) uses native array copying inside.
That's it :)
Best regards!
All of The responders gave good answers. However, I am giving you all relatable methods for this so that any one can get from one place, I'll edit my answer if I find something new.
substring(0)- use for cut string from given specific char.
Substring(0,2)- give you sub string from starting(0) and ending(2) characters.
Split("NAME")- return you string in two parts first is that you use in split "NAME" and another part is rest of string combine.
subSequence(0,3) - returns sequence of give start(0) and ending index(3).
This one is not specifically use for split string but though it may be use full for some one
startswith("A",3)- returns string for specific starting character.
For example:
String s = "StackOverflow";
String[] split = s.split("Stack");
System.out.println("STRING NAME:"+s.substring(2));
System.out.println("STRING NAME:"+s.substring(2,3));
System.out.println("STRING NAME:"+split[1]);
System.out.println("STRING NAME:"+split[0]);
System.out.println("STRING NAME:"+s.subSequence(2,5));
Output:
1)ackOverflow
2)a
3)Overflow
4)stack
5)ack
I hope this will give you enough information that you require.

Categories

Resources