Using remove() and indexOf() with SortedList

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Using remove() and indexOf() with SortedList

Daniel-16

Hi,

I'm just getting started with GlazedLists so I wrote a simple program to display some songs in a table. The SortedList.remove(Object) and SortedList.indexOf() work fine at first, but then a problem appears as soon as the user clicks on a column to sort by that column. The problem is that if that column contains duplicate values, then remove() and indexOf() will always operate on the object with the "first matching value", regardless of whether it's the correct object or not.

That explanation is a bit confusing, so I've whipped up a simple example that hopefully demonstrates the problem more clearly (see source at the bottom). I'm just adding 2 Song objects to a SortedList, where a Song contains an artist and a title. The output is as follows:

    Initial list contents:
    [incubus/drive, incubus/stellar]

    Indexes before sorting by column:
    incubus/drive: 0
    incubus/stellar: 1

    Indexes after sorting by column:
    incubus/drive: 0
    incubus/stellar: 0

    List contents after removing incubus/stellar:
    [incubus/stellar]

I suspect the reason for this behavior is that, when the user clicks on a column to sort it, SortedList.setComparator() is called with some sort of comparator for that column, and this "column comparator" is then used by the remove() and indexOf() methods.

So my question is: how can you remove and check indexes of objects in a SortedList? A workaround for the remove() is to call remove() on the base EventList, but this is slower because it's just a regular list with no indexing (no tree/map). However, I still don't see any way to do an indexOf(). If your SortedList contains Song objects then, given a particular Song object, how can you find the index of that object in the list?

Thanks,
Daniel

EXAMPLE SOURCE CODE
-------------------

import java.util.*;
import javax.swing.*;
import ca.odell.glazedlists.*;
import ca.odell.glazedlists.gui.*;
import ca.odell.glazedlists.swing.*;

public class GlazedSortTest
{
    public static void main(String[] args)
    {
        EventList eventList = GlazedLists.eventList(new ArrayList());
        SortedList sortedList = new SortedList(eventList);

        // Create 2 songs with the same artist and add to list
        Song incubusDrive = new Song(1, "incubus", "drive");
        Song incubusStellar = new Song(2, "incubus", "stellar");
        Song[] songs = new Song[] { incubusDrive, incubusStellar };
        sortedList.add(incubusDrive);
        sortedList.add(incubusStellar);

        // Create a table
        EventTableModel model =
            new EventTableModel(sortedList, new SongTableFormat());
        JTable table = new JTable(model);
        TableComparatorChooser tableCompChooser =
            new TableComparatorChooser(table, sortedList, false);

        // Print out initial list contents and indexes
        System.out.println("\nInitial list contents:\n" + sortedList);
        System.out.println("\nIndexes before sorting by column:");
        printIndexes(sortedList, songs);

        // Now "pretend" that the user click on the Artist column to
        // sort it (i.e. set first column as the sorted column)
        tableCompChooser.chooseComparator(0, 0, false);

        // Check indexes again
        System.out.println("\nIndexes after sorting by column:");
        printIndexes(sortedList, songs);

        // Remove second song and check the contents again
        sortedList.remove(incubusStellar);
        System.out.println("\nList contents after removing " +
            incubusStellar + ":\n" + sortedList);
    }

    private static void printIndexes(SortedList sortedList, Song[] songs)
    {
        for (int i = 0; i < songs.length; i++)
            System.out.println(songs[i] + ": " + sortedList.indexOf(songs[i]));
    }

    private static class SongTableFormat implements TableFormat
    {
        public int getColumnCount()
        {
            return 2;
        }

        public String getColumnName(int column)
        {
            if (column == 0)
                return "Artist";
            else
                return "Title";
        }

        public Object getColumnValue(Object baseObject, int column)
        {
            if (column == 0)
                return ((Song)baseObject).artist;
            else
                return ((Song)baseObject).title;
        }
    }

    private static class Song implements Comparable
    {
        public int id;
        public String artist;
        public String title;

        public Song(int id, String artist, String title)
        {
            this.id = id;
            this.artist = artist;
            this.title = title;
        }

        public int compareTo(Object o)
        {
            return new Integer(id).compareTo(new Integer(((Song)o).id));
        }

        public String toString()
        {
            return artist + "/" + title;
        }
    }
}


_______________________________________________
Join Excite! - http://www.excite.com
The most personalized portal on the Web!



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Using remove() and indexOf() with SortedList

James Lemieux
Daniel,
 
     You have uncovered a bug in SortedList. We're attempting to exploit the sorted nature of the data a little too aggressively, and have work to do for cases like the one you elegantly described, where the comparator will not produce the same value as .equals(). Rest assured this will be a high priority bug for us to fix. I have filed this bug on your behalf here:
 
 
and we'll work to close it as soon as possible.
 
thanks for taking the time to write to the users list,
 
James.
 
PS: If you're very new to glazedlists, I suggest watching our screencasts for a quick intro to how various glazed lists works. They're available here:
 


 
On 8/12/05, Daniel <[hidden email]> wrote:

Hi,

I'm just getting started with GlazedLists so I wrote a simple program to display some songs in a table. The SortedList.remove(Object) and SortedList.indexOf() work fine at first, but then a problem appears as soon as the user clicks on a column to sort by that column. The problem is that if that column contains duplicate values, then remove() and indexOf() will always operate on the object with the "first matching value", regardless of whether it's the correct object or not.

That explanation is a bit confusing, so I've whipped up a simple example that hopefully demonstrates the problem more clearly (see source at the bottom). I'm just adding 2 Song objects to a SortedList, where a Song contains an artist and a title. The output is as follows:

   Initial list contents:
   [incubus/drive, incubus/stellar]

   Indexes before sorting by column:
   incubus/drive: 0
   incubus/stellar: 1

   Indexes after sorting by column:
   incubus/drive: 0
   incubus/stellar: 0

   List contents after removing incubus/stellar:
   [incubus/stellar]

I suspect the reason for this behavior is that, when the user clicks on a column to sort it, SortedList.setComparator () is called with some sort of comparator for that column, and this "column comparator" is then used by the remove() and indexOf() methods.

So my question is: how can you remove and check indexes of objects in a SortedList? A workaround for the remove() is to call remove() on the base EventList, but this is slower because it's just a regular list with no indexing (no tree/map). However, I still don't see any way to do an indexOf(). If your SortedList contains Song objects then, given a particular Song object, how can you find the index of that object in the list?

Thanks,
Daniel

EXAMPLE SOURCE CODE
-------------------

import java.util.*;
import javax.swing.*;
import ca.odell.glazedlists.*;
import ca.odell.glazedlists.gui.*;
import ca.odell.glazedlists.swing.* ;

public class GlazedSortTest
{
   public static void main(String[] args)
   {
       EventList eventList = GlazedLists.eventList(new ArrayList());
       SortedList sortedList = new SortedList(eventList);

       // Create 2 songs with the same artist and add to list
       Song incubusDrive = new Song(1, "incubus", "drive");
       Song incubusStellar = new Song(2, "incubus", "stellar");
       Song[] songs = new Song[] { incubusDrive, incubusStellar };
       sortedList.add(incubusDrive);
       sortedList.add(incubusStellar);

       // Create a table
       EventTableModel model =
           new EventTableModel(sortedList, new SongTableFormat());
       JTable table = new JTable(model);
       TableComparatorChooser tableCompChooser =
           new TableComparatorChooser(table, sortedList, false);

       // Print out initial list contents and indexes
       System.out.println("\nInitial list contents:\n" + sortedList);
       System.out.println("\nIndexes before sorting by column:");
       printIndexes(sortedList, songs);

       // Now "pretend" that the user click on the Artist column to
       // sort it (i.e. set first column as the sorted column)
       tableCompChooser.chooseComparator (0, 0, false);

       // Check indexes again
       System.out.println("\nIndexes after sorting by column:");
       printIndexes(sortedList, songs);

       // Remove second song and check the contents again
       sortedList.remove(incubusStellar);
       System.out.println("\nList contents after removing " +
           incubusStellar + ":\n" + sortedList);
   }

   private static void printIndexes(SortedList sortedList, Song[] songs)
   {
       for (int i = 0; i < songs.length; i++)
           System.out.println(songs[i] + ": " + sortedList.indexOf(songs[i]));
   }

   private static class SongTableFormat implements TableFormat
   {
       public int getColumnCount()
       {
           return 2;
       }

       public String getColumnName(int column)
       {
           if (column == 0)
               return "Artist";
           else
               return "Title";
       }

       public Object getColumnValue(Object baseObject, int column)
       {
           if (column == 0)
               return ((Song)baseObject).artist;
           else
               return ((Song)baseObject).title;
       }
   }

   private static class Song implements Comparable
   {
       public int id;
       public String artist;
       public String title;

       public Song(int id, String artist, String title)
       {
           this.id = id;
           this.artist = artist;
           this.title = title;
       }

       public int compareTo(Object o)
       {
           return new Integer(id).compareTo(new Integer(((Song)o).id));
       }

       public String toString()
       {
           return artist + "/" + title;
       }
   }
}


_______________________________________________
Join Excite! - http://www.excite.com
The most personalized portal on the Web!



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Using remove() and indexOf() with SortedList

James Lemieux
Daniel,

     The bug you uncovered in SortedList has been fixed.

https://glazedlists.dev.java.net/issues/show_bug.cgi?id=255

     You can safely move up to the latest build from CVS located here:

https://glazedlists.dev.java.net/files/documents/1073/18783/glazedlists.jar

and continue with your Glazing.

thanks much,

James.

On 8/12/05, James Lemieux <[hidden email]> wrote:
Daniel,
 
     You have uncovered a bug in SortedList. We're attempting to exploit the sorted nature of the data a little too aggressively, and have work to do for cases like the one you elegantly described, where the comparator will not produce the same value as .equals(). Rest assured this will be a high priority bug for us to fix. I have filed this bug on your behalf here:
 
<a href="https://glazedlists.dev.java.net/issues/show_bug.cgi?id=255" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">https://glazedlists.dev.java.net/issues/show_bug.cgi?id=255
 
and we'll work to close it as soon as possible.
 
thanks for taking the time to write to the users list,
 
James.
 
PS: If you're very new to glazedlists, I suggest watching our screencasts for a quick intro to how various glazed lists works. They're available here:
 
<a href="http://www.publicobject.com/glazedlistsdeveloper/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">http://www.publicobject.com/glazedlistsdeveloper/


 
On 8/12/05, Daniel <[hidden email]> wrote:

Hi,

I'm just getting started with GlazedLists so I wrote a simple program to display some songs in a table. The SortedList.remove(Object) and SortedList.indexOf() work fine at first, but then a problem appears as soon as the user clicks on a column to sort by that column. The problem is that if that column contains duplicate values, then remove() and indexOf() will always operate on the object with the "first matching value", regardless of whether it's the correct object or not.

That explanation is a bit confusing, so I've whipped up a simple example that hopefully demonstrates the problem more clearly (see source at the bottom). I'm just adding 2 Song objects to a SortedList, where a Song contains an artist and a title. The output is as follows:

   Initial list contents:
   [incubus/drive, incubus/stellar]

   Indexes before sorting by column:
   incubus/drive: 0
   incubus/stellar: 1

   Indexes after sorting by column:
   incubus/drive: 0
   incubus/stellar: 0

   List contents after removing incubus/stellar:
   [incubus/stellar]

I suspect the reason for this behavior is that, when the user clicks on a column to sort it, SortedList.setComparator () is called with some sort of comparator for that column, and this "column comparator" is then used by the remove() and indexOf() methods.

So my question is: how can you remove and check indexes of objects in a SortedList? A workaround for the remove() is to call remove() on the base EventList, but this is slower because it's just a regular list with no indexing (no tree/map). However, I still don't see any way to do an indexOf(). If your SortedList contains Song objects then, given a particular Song object, how can you find the index of that object in the list?

Thanks,
Daniel

EXAMPLE SOURCE CODE
-------------------

import java.util.*;
import javax.swing.*;
import ca.odell.glazedlists.*;
import ca.odell.glazedlists.gui.*;
import ca.odell.glazedlists.swing.* ;

public class GlazedSortTest
{
   public static void main(String[] args)
   {
       EventList eventList = GlazedLists.eventList(new ArrayList());
       SortedList sortedList = new SortedList(eventList);

       // Create 2 songs with the same artist and add to list
       Song incubusDrive = new Song(1, "incubus", "drive");
       Song incubusStellar = new Song(2, "incubus", "stellar");
       Song[] songs = new Song[] { incubusDrive, incubusStellar };
       sortedList.add(incubusDrive);
       sortedList.add(incubusStellar);

       // Create a table
       EventTableModel model =
           new EventTableModel(sortedList, new SongTableFormat());
       JTable table = new JTable(model);
       TableComparatorChooser tableCompChooser =
           new TableComparatorChooser(table, sortedList, false);

       // Print out initial list contents and indexes
       System.out.println("\nInitial list contents:\n" + sortedList);
       System.out.println("\nIndexes before sorting by column:");
       printIndexes(sortedList, songs);

       // Now "pretend" that the user click on the Artist column to
       // sort it (i.e. set first column as the sorted column)
       tableCompChooser.chooseComparator (0, 0, false);

       // Check indexes again
       System.out.println("\nIndexes after sorting by column:");
       printIndexes(sortedList, songs);

       // Remove second song and check the contents again
       sortedList.remove(incubusStellar);
       System.out.println("\nList contents after removing " +
           incubusStellar + ":\n" + sortedList);
   }

   private static void printIndexes(SortedList sortedList, Song[] songs)
   {
       for (int i = 0; i < songs.length; i++)
           System.out.println(songs[i] + ": " + sortedList.indexOf(songs[i]));
   }

   private static class SongTableFormat implements TableFormat
   {
       public int getColumnCount()
       {
           return 2;
       }

       public String getColumnName(int column)
       {
           if (column == 0)
               return "Artist";
           else
               return "Title";
       }

       public Object getColumnValue(Object baseObject, int column)
       {
           if (column == 0)
               return ((Song)baseObject).artist;
           else
               return ((Song)baseObject).title;
       }
   }

   private static class Song implements Comparable
   {
       public int id;
       public String artist;
       public String title;

       public Song(int id, String artist, String title)
       {
           <a href="http://this.id" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">this.id = id;
           this.artist = artist;
           this.title = title;
       }

       public int compareTo(Object o)
       {
           return new Integer(id).compareTo(new Integer(((Song)o).id));
       }

       public String toString()
       {
           return artist + "/" + title;
       }
   }
}


_______________________________________________
Join Excite! - <a href="http://www.excite.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">http://www.excite.com
The most personalized portal on the Web!



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]