Showing posts with label lists. Show all posts
Showing posts with label lists. Show all posts

08 August 2013

Android, extending listView functinality


Android listViews are pretty useful and pretty simple. You have to get your head around some sort of adapter, but that's no huge issue.

However I've previously never bothered to find out how to get more than one column on a listView. Luckily this is much easier than I first thought. My example uses contentProvidors to setup the cursor, but I think this should work with DB stuff as well. Given a bit of hocus pocus.

I'm not going to go into the contentProvidor stuff here as it's a big subject and developer.android do a pretty good job:
http://developer.android.com/guide/topics/providers/content-provider-basics.html

First setup your activity_main.xml layout file:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <ListView
  android:id="@+id/listView1"
  android:layout_width="wrap_content"
  android:layout_height="350dp"
  android:layout_alignParentBottom="true"
  android:layout_centerHorizontal="true" >
 </ListView>

</RelativeLayout>


Next add a new xml file to the res/layout folder (mine is named contacts_single.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="horizontal" >

 <TextView
  android:id="@+id/name_entry"
  android:layout_width="100dp"
  android:layout_height="wrap_content" />
 
 <TextView
  android:id="@+id/number_entry"
  android:layout_width="100dp"
  android:layout_height="wrap_content" />

</LinearLayout>


Now move to the MainActivity or wherever your display function will be and you'll need something like this:

private void outputCursor(){
 // Defines a list of columns which we have defined in our cursor, and will be output to listView
 String[] mWordListColumns =
 {
  ContactsContract.Contacts._ID,
  ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
  
 };

 // Defines a list of View IDs. These are IDs of textViews defined in a serperate layout file
 int[] mWordListItems = { R.id.name_entry, R.id.number_entry};

 // Creates a new SimpleCursorAdapter
 SimpleCursorAdapter mCursorAdapter = new SimpleCursorAdapter(
  getApplicationContext(),   // The application's Context object
  R.layout.contacts_single,   // A layout in XML for one row in the ListView
  mCursor,     // The result from the query
  mWordListColumns,    // A string array of column names in the cursor
  mWordListItems,     // An integer array of view IDs in the row layout
  0      // Flags (usually none are needed)
 );

 // Sets the adapter for the ListView
 ListView myListView = (ListView) findViewById(R.id.listView1);
 myListView.setAdapter(mCursorAdapter);
}

That should be all you need. Note the mWordListItems is passed into the adapter and the R.layout.contacts_single reference, telling the adapter to use these custom elements to display its contents. Then we get the ListView from the original activity and set the adapter. Simples!

22 November 2012

ColdFusion - Find common elements in two lists

I recently stumbled across an interesting programming question, how to find the duplicates in two lists? In this case I had two lists of email addresses and wanted to know which email addresses were in both lists. Sounds simple.

I'm curious to know what is the optimum approach, both in terms of simplicity and in terms of speed.

The first solution (compareLists) is the one I came up with, the second (listCommon) is one I adapted a little from Phillip's Coldfusion Blog.

<cffunction name="compareLists" access="public" returnType="string" output="false">
    <cfargument name="strList1" type="string" required="true" />
    <cfargument name="strList2" type="string" required="true" />

    <cfscript>
        var stuCompare        = {};
        var intCount        = 0;
        var strTempElement    = "";
        
        //loop through second list
        for(intCount=1; intCount LTE listLen(arguments.strList2); intCount++){
            strTempElement    = listGetAt(arguments.strList2,intCount);
            if(listContainsNoCase(arguments.strList1,strTempElement)){
                //Add key to struct
                stuCompare[strTempElement]    = "";
            }
        }
    
        return structKeyList(stuCompare);
    </cfscript>
</cffunction>

<cffunction name="listCommon" access="public" output="false" returnType="string">
    <cfargument name="strList1" type="string" required="true" />
    <cfargument name="strList2" type="string" required="true" />
     
    <cfset var arrList1 = ListToArray(arguments.strList1) />
    <cfset var arrList2 = ListToArray(arguments.strList2) />
     
    <cfset arrList1.retainAll(arrList2) />
     
    <!--- Return in list format --->
    <cfreturn ArrayToList(arrList1) />
</cffunction>

I was a little surprised you could use a java function like retainAll quite so nativity, but other than that it's fairly self explanatory.
So to time the methods, I took a leaf out of Ben Nadel's book and used getTickCount() to count the processing of 10,000 iterations of the above functions with two small lists.

Function Name Time (in milliseconds)
compareLists 849
listCommon 611
compareLists 352
listCommon 182
compareLists 232
listCommon 234
compareLists 208
listCommon 151
compareLists 80
listCommon 104

So as you can see, the listCommon method is much quicker. However it seems after the first few runs, caching kicks in and from then on the compareLists method remains very fast. I don't really want to get into caching, I'd rather focus on the differences between the two methods. Does anyone have any suggestions or input? Anyone got any examples of how they'd do this kind of thing in Java or possibly even something lower level?