Trying to use a loop to set the text of 12 checkboxes from a db query. Would like to substitute "add1" with an array value and loop through all 12 instead of spelling out each one. Any ideas of how to do this?
Here is the code I am trying to modify:
add1Text= (CheckBox) findViewById(R.id.add1);
if (cursor.getString(cursor.getColumnIndex("add1")) == null) {
add1Text.setVisibility(View.GONE);
}
else {
add1Text.setText(cursor.getString(cursor.getColumnIndex("add1")));
}
Please note: everything below is off the top of my head, I can't test it right now. I'll test it later when I get a chance.
I think you'll need to keep track of which column to associate with each CheckBox... I'm presuming it's something like this:
Column: add1 => Checkbox: add1Text
Column: add2 => Checkbox: add2Text
and so on and so forth.
In this circumstance, you'll need to manually keep track of them, possibly in an array. I'd suggest making a Pair class that you can use. I've altered the class from this post [ A Java collection of value pairs? (tuples?) ]
public class Pair<L,R> {
private final L left;
private final R right;
public Pair(L left, R right) {
this.left = left;
this.right = right;
}
public L getLeft() { return left; }
public R getRight() { return right; }
#Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }
#Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}
}
Now, you'll need to make a List (or similar) containing the pairs that you want.
List<Pair<CheckBox, String>> list = new ArrayList<Pair<CheckBox, String>>;
list.add(new Pair<CheckBox, String>((CheckBox) findViewById(R.id.add1), "add1");
list.add(new Pair<CheckBox, String>((CheckBox) findViewById(R.id.add2), "add2");
list.add(new Pair<CheckBox, String>((CheckBox) findViewById(R.id.add3), "add3");
and so on and so forth
Then you can iterate through the List using something like
foreach (Pair<CheckBox, String> item in list)
{
if (cursor.getString(cursor.getColumnIndex(item.getLeft()) == null)
{
item.getRight().setVisibility(View.GONE);
}
else
{
item.getRight().setText(cursor.getString(cursor.getColumnIndex(item.getLeft()));
}
}
Got it! Forgot that I was dealing with objects and also realized I needed a third array. Here is what I came up with.
cList contains column names
fList are the objects (in this case CheckBoxes)
pList are the names of the objects I am selecting from the layout.
Object fList[]={add1Text,add2Text,add3Text};
int pList[]={R.id.add1,R.id.add2,R.id.add3};
cList = cursor.getColumnNames();
for (int i =0; i < fList.length; i++){
fList[i] = (CheckBox) findViewById(pList[i]);
if (cursor.getString(cursor.getColumnIndex(cList[i])) == null) {
((TextView) fList[i]).setVisibility(View.GONE);
}
else {
((TextView) fList[i]).setText(cList[i] + " - " + cursor.getString(cursor.getColumnIndex( cList[i])));
}
}
Sets the CheckBox text to ( Column name - Value )
Related
Im having troubles with Android SortedList in RecyclerView, mainly with the remove method:
public void replaceAll(List userFertList, List defaultFertList){
restartIndexes(userFertList, defaultFertList);
mComparator.swapLists(Utils.fertiliserListToNameList(userFertList));
List<Fertiliser> combinedList = Utils.combineFertLists(userFertList, defaultFertList);
mSortedList.beginBatchedUpdates();
for (int i = mSortedList.size() -1; i > -1 ; i--) {
final Fertiliser fertiliser = mSortedList.get(i);
if(!combinedList.contains(fertiliser)){
if(!mSortedList.remove(fertiliser)){
throw new RuntimeException();
};
}
}
mSortedList.addAll(combinedList);
mSortedList.endBatchedUpdates();
}
The above code is executed when filtering the list. All of the objects that are not present in the new list are removed. However the call to remove objects sometimes fail. I know the object is present, because it's taken from the SortedList itself.
My research hinted me there's something wrong with my Comparator compare method:
#Override
public int compare(Fertiliser fertiliser, Fertiliser t1) {
if(fertiliser == t1){
return 0;
}
if(mUserFertNames.contains(fertiliser.getName()) != mUserFertNames.contains(t1.getName())){
return mUserFertNames.contains(fertiliser.getName()) ? -1 : 1;
} else {
return fertiliser.getName().compareToIgnoreCase(t1.getName());
}
}
Im sorting by two criteria (one that checks if the object is present in a list and by name).
So my thinking is, because SortedList uses the Comparator to locate the element, my Comparator gives false results, and the list cannot find the item:
The called method from the SortedList:
private int findIndexOf(T item, T[] mData, int left, int right, int reason) {
while (left < right) {
final int middle = (left + right) / 2;
T myItem = mData[middle];
final int cmp = mCallback.compare(myItem, item);
if (cmp < 0) {
left = middle + 1;
} else if (cmp == 0) {
if (mCallback.areItemsTheSame(myItem, item)) {
return middle;
} else {
int exact = linearEqualitySearch(item, middle, left, right);
if (reason == INSERTION) {
return exact == INVALID_POSITION ? middle : exact;
} else {
return exact;
}
}
} else {
right = middle;
}
}
return reason == INSERTION ? left : INVALID_POSITION;
}
However i coudn't find a solution. Can you help me?
P.S. When i examined the error, both objects were not in the list (so they were compared by names only).
Try .removeItemAt(i) instead of .remove(fertiliser). This worked for me while list was filtered.
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);
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);
}
I have two lists of Default and Chrome browsers history.
I want to merge these two lists into one list.
I need to update item if I find it duplicate (is common between two lists).
So, my "BrowserRecord" class is like this:
public class BrowserRecord {
private long id;
private int bookmark;
private long created;
private long date;
private String title;
private String url;
private long visits;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BrowserRecord record = (BrowserRecord) o;
return url.equals(record.url);
}
#Override
public int hashCode() {
return url.hashCode();
}
// other getter setter methods
...
}
and finally, I have a method that gets browsers histories and does merging:
public List<BrowserRecord> getHistory() {
List<BrowserRecord> browserList = new ArrayList<BrowserRecord>();
// get history of default and chrome browsers
List<BrowserRecord> defaultList = getDefaultBrowserHistory();
List<BrowserRecord> chromeList = getChromeBrowserHistory();
Log.e(TAG, "=> size of Default browser:" + defaultList.size());
Log.e(TAG, "=> size of Chrome browser:" + chromeList.size());
// compare list A with B, update A item if equal item found in B and push it to tempList
for(int i=0; i<chromeList.size(); i++) {
BrowserRecord chromeBrowser = chromeList.get(i);
for(int j=0; j<defaultList.size(); j++) {
BrowserRecord defaultBrowser = defaultList.get(j);
if(chromeBrowser.equals(defaultBrowser)) {
if(chromeBrowser.getBookmark() != defaultBrowser.getBookmark())
chromeBrowser.setBookmark(1);
chromeBrowser.setVisits(chromeBrowser.getVisits() + defaultBrowser.getVisits());
}
}
browserList.add(chromeBrowser);
}
// compare list B with A, jump if equal item found in A, push to tempList if item not found
for(int i=0; i<defaultList.size(); i++) {
BrowserRecord defaultBrowser = defaultList.get(i);
boolean found = false;
for(int j=0; j<chromeList.size(); j++) {
BrowserRecord chromeBrowser = chromeList.get(j);
if(defaultBrowser.equals(chromeBrowser)) {
found = true;
break;
}
}
if(!found)
browserList.add(defaultBrowser);
}
Log.e(TAG, "=> size of final browser:" + browserList.size());
return browserList;
}
I have tested this method and is working fine. Since my history records on mobile device after 3 years didn't exceed more than 200 records on one list and 150 for others, I assume something similar is happening for other users. But I'm sure is not optimum way.
What do you recommend?
any suggestion would be appreciated. Thanks.
Not sure I understand correctly, but it seems like what you're trying to do is, given both lists, create a final list which will contain all of the elements from both lists, removing any duplicates.
If this is the case, then take a look at Java's TreeSet class. If you iterate over all of the elements from both your lists and insert them into a TreeSet, you will basically get the result you're looking for. You can then use an Iterator to create an ArrayList containing all of the non-duplicate items from both your lists. As a side-effect of using a TreeSet, they will ordered (you can also use either a HashSet if you don't care about the order or a LinkedHashSet if you want to preserve the order of insertion).
When parsing the SoapObject data into a String[], the empty fields in the response from the webservice do not get added to it and I can't identify the empty propeties by checking for null or "".
So my problem is basically: The SoapObject contains the right amount of properties, but the parsed result (String[]) does not contain the ones that are empty, nor can I check for empty properties and add "" to the String[].
This causes problems for me when saving to the SQLite DB since every e.g. "User" contains a different amount of fields.
public static String[] getStringArrayResponse(SoapObject node, Vector<String> strings) {
boolean isFirstCall = false;
if (strings == null) {
isFirstCall = true;
strings = new Vector<String>();
}
int count = node.getPropertyCount();
for (int i = 0; i < count; i++) {
Object obj1 = node.getProperty(i);
if (obj1 instanceof SoapObject) {
if (((SoapObject)obj1).getPropertyCount() > 0) {
// Returns the correct amount of properties
Log.d("PARSER", "propertycount = " +((SoapObject)obj1).getPropertyCount());
getStringArrayResponse((SoapObject)obj1, strings);
}
} else if (obj1 instanceof SoapPrimitive) {
strings.add(((SoapPrimitive)obj1).toString());
}
}
if (isFirstCall) {
return (String[])strings.toArray(new String[strings.size()]);
}
return null;
}
This is really giving me a headache and I'm grateful for any help I can get :)
I needed to check for "AnyType{}" :)
if (obj1.toString().equals("anyType{}")){
strings.add("");
}
Just added this block of code below the else if.