 |
|
|
|
| Author |
Message |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Wed Dec 12, 2007 8:50 pm Post subject: not sure if there is an easy way to do this! |
|
|
Hi I have an array list in C# and I need to remove duplicates of data groups
in an array list. After the array list is populated each group of data is 5
elements in order (0-4,5-9,10-14), name (string), number (string),
user(string), startdate(datetime), enddate(datetime). So it might look like
arraylist[0]="truck";
arraylist[1]="242";
arraylist[2]="tom";
arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
//start of next group
arraylist[5]="car";
When the array is filled it has several hundred values by reading data from
a webservice, but I only want to remove values when all 5 elements of each
group matches another group so I am left with only the unique groups.
Thanks Paul.
--
Paul G
Software engineer.
Archived from group: microsoft>public>dotnet>languages>csharp |
|
| Back to top |
|
 |
Jon Skeet [C# MVP]
Joined: 08 Aug 2007 Posts: 266
|
Posted: Thu Dec 13, 2007 5:20 am Post subject: Re: not sure if there is an easy way to do this! |
|
|
Paul wrote:
> Hi I have an array list in C# and I need to remove duplicates of data groups
> in an array list. After the array list is populated each group of data is 5
> elements in order (0-4,5-9,10-14), name (string), number (string),
> user(string), startdate(datetime), enddate(datetime). So it might look like
> arraylist[0]="truck";
> arraylist[1]="242";
> arraylist[2]="tom";
> arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
> arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
> //start of next group
> arraylist[5]="car";
> When the array is filled it has several hundred values by reading data from
> a webservice, but I only want to remove values when all 5 elements of each
> group matches another group so I am left with only the unique groups.
Well the first thing I'd do is add a little encapsulation. Convert this
mixed-type list into one where each element is the same type - an
object encapsulating the name, number, user, start date and end date.
At that point, removing duplicates is *relatively* straightforward -
override Equals and GetHashCode in your new type, create a Hashtable of
them, put all the entries in (mapping to themselves, for example - it's
only the keys which are important) and then just get the keys out.
--
Jon Skeet -
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk |
|
| Back to top |
|
 |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Wed Dec 12, 2007 9:32 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
Hi Jon, thanks for the information. Just wondering if you could provide a
brief example, I can convert all to the same type, but am not sure about
object encapsulating the name, number, user, start date and end date. I have
not worked with hash tables but I think I understand the general concept.
Hash table
key object
1 (contains 5 grouped items)
--
Paul G
Software engineer.
"Jon Skeet [C# MVP]" wrote:
> Paul wrote:
> > Hi I have an array list in C# and I need to remove duplicates of data groups
> > in an array list. After the array list is populated each group of data is 5
> > elements in order (0-4,5-9,10-14), name (string), number (string),
> > user(string), startdate(datetime), enddate(datetime). So it might look like
> > arraylist[0]="truck";
> > arraylist[1]="242";
> > arraylist[2]="tom";
> > arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
> > arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
> > //start of next group
> > arraylist[5]="car";
> > When the array is filled it has several hundred values by reading data from
> > a webservice, but I only want to remove values when all 5 elements of each
> > group matches another group so I am left with only the unique groups.
>
> Well the first thing I'd do is add a little encapsulation. Convert this
> mixed-type list into one where each element is the same type - an
> object encapsulating the name, number, user, start date and end date.
>
> At that point, removing duplicates is *relatively* straightforward -
> override Equals and GetHashCode in your new type, create a Hashtable of
> them, put all the entries in (mapping to themselves, for example - it's
> only the keys which are important) and then just get the keys out.
>
> --
> Jon Skeet -
> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
> World class .NET training in the UK: http://iterativetraining.co.uk
> |
|
| Back to top |
|
 |
Jon Skeet [C# MVP]
Joined: 08 Aug 2007 Posts: 266
|
Posted: Thu Dec 13, 2007 5:44 am Post subject: Re: not sure if there is an easy way to do this! |
|
|
Paul wrote:
> Hi Jon, thanks for the information. Just wondering if you could provide a
> brief example, I can convert all to the same type, but am not sure about
> object encapsulating the name, number, user, start date and end date. I have
> not worked with hash tables but I think I understand the general concept.
> Hash table
> key object
> 1 (contains 5 grouped items)
Something like (replace Foo with a useful name - I don't know what your
groups really represent):
public class Foo
{
readonly string name;
readonly string number; // Misnomer?
readonly string user;
readonly DateTime startDate;
readonly DateTime endDate;
public Foo(string name, string number, string user,
DateTime startDate, DateTime endDate)
{
this.name = name;
this.number = number;
this.user = user;
this.startDate = startDate;
this.endDate = endDate;
}
// Put properties supporting the variables in here
public override bool Equals(object other)
{
Foo otherFoo = other as Foo;
if (otherFoo==null)
{
return false;
}
return otherFoo.name==name &&
otherFoo.number==number &&
otherFoo.user==user &&
otherFoo.startDate==startDate &&
otherFoo.endDate==endDate;
}
public override int GetHashCode()
{
int hash = 17;
hash = hash*23 + name.GetHashCode();
hash = hash*23 + number.GetHashCode();
hash = hash*23 + user.GetHashCode();
hash = hash*23 + startDate.GetHashCode();
hash = hash*23 + endDate.GetHashCode();
return hash;
}
}
To convert the list, you'd do something like:
Hashtable grouped = new Hashtable();
for (int i=0; i < original.Count/5; i++)
{
Foo foo = new Foo ((string)original[i*5],
(string)original[i*5+1]
(string)original[i*5+2]
(DateTime)original[i*5+3]
(DateTime)original[i*5+4]);
grouped[foo] = foo;
}
Then use grouped.Keys to get at them.
--
Jon Skeet -
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk |
|
| Back to top |
|
 |
Alun Harford
Joined: 08 Aug 2007 Posts: 9
|
Posted: Thu Dec 13, 2007 5:47 am Post subject: Re: not sure if there is an easy way to do this! |
|
|
Paul wrote:
> Hi I have an array list in C# and I need to remove duplicates of data groups
> in an array list. After the array list is populated each group of data is 5
> elements in order (0-4,5-9,10-14), name (string), number (string),
> user(string), startdate(datetime), enddate(datetime). So it might look like
> arraylist[0]="truck";
> arraylist[1]="242";
> arraylist[2]="tom";
> arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
> arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
> //start of next group
> arraylist[5]="car";
> When the array is filled it has several hundred values by reading data from
> a webservice, but I only want to remove values when all 5 elements of each
> group matches another group so I am left with only the unique groups.
Using C# 3 here...
Well you make your own data type. In this case, I'll make a struct
(since I'm assuming this is pure data with no behavior attached - and
because I'm to write the Equals() and GetHashCode() methods to make a
complete example with a proper class).
public struct MyType
{
public string Name { get; set; }
public string Number /* Eugh! */ { get; set; }
public string User { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public MyType(IList items, int startIndex) {
Name = items[startIndex];
Number = items[startIndex + 1];
User = items[startIndex + 2];
StartDate = items[startIndex + 3];
EndDate = items[startIndex + 4];
}
}
You can now make a method in another class:
public List GetDistinctElements(IList items) {
if(items==null) throw new ArgumentNullException("items");
if(items.Count%5!=0) throw new ArgumentException("items.Count%5!=0");
List result = new List();
for(int i=0;i
result.Add(new MyType(items, i));
}
return result.Distinct();
}
As an added bonus, you get your data in a sensible data type.
Alun Harford |
|
| Back to top |
|
 |
Peter Duniho
Joined: 08 Aug 2007 Posts: 45
|
Posted: Wed Dec 12, 2007 9:55 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
On Wed, 12 Dec 2007 15:50:02 -0800, Paul
wrote:
> Hi I have an array list in C# and I need to remove duplicates of data
> groups
> in an array list. After the array list is populated each group of data
> is 5
> elements in order (0-4,5-9,10-14), name (string), number (string),
> user(string), startdate(datetime), enddate(datetime).
I would say that this example is a great example of how _not_ to store
your data, as well as an example of the hazards of using a type-agnostic
data structure like ArrayList.
I think it's a really bad idea to store data items in a collection in the
way you've done it. For a variety of reasons, but mainly because a
collection ought to have a direct mapping between a single data type and
an element in the collection. There's no way to describe what your
collection actually contains, because each element is different from 80%
of the other elements.
As far as your specific question goes...
I would first suggest that you stop using an ArrayList like that. Create
a new data structure that contains each of the data elements you're
referencing, and then store that data structure in a collection. Then,
make sure the new data structure implements IComparable, so that you can
do things like sorting and comparing for equality.
Then you can just store the data in a List, sorting the list after
you've received all of the data and removing the duplicates with a linear
scan through the list. Yet another alternative would be to use a
SortedList, adding items only if they already aren't in the list. This
avoids having to sort at the end, but of course you have the overhead of
inserting elements as you go along.
Alternatively, you can use a Dictionary containing your data, with the
data structure itself being its own key. That provides a fast and
convenient way to ensure that you only ever have one instance of any given
group of data. You'd have to override the Object.GetHashCode() method for
your new data structure though, basing your hash code on the data in the
object.
A dictionary would be faster than the sorted list, with the trade-off that
it requires you also implement GetHashCode(), and of course you don't get
a sorted list of data in the end (but that may not be needed anyway).
If for some reason you _must_ have this data in an ArrayList that looks
like what you've described, I would still do the above, but the convert
the results back to an ArrayList as needed. You could either brute-force
the problem by scanning the ArrayList considering five elements at a time
(easy to write, but terrible performance), or manually sorting the list,
again using five elements at a time for the sort (harder to write, but
good performance). But the framework won't give you any help there, and
while it's not hard to implement your own sort, it would be a pain
(especially given the "five elements at a time" requirement that would
lead you to have to do that in the first place) and certainly much more
trouble than just creating a new structure that implements IComparable.
If you have a data structure like this:
struct DataItem : IComparable
{
readonly string Name;
readonly int Number;
readonly string User;
readonly DateTime StartDate;
readonly DateTime EndDate;
public DataItem(string Name, int Number, string User, DateTime
StartDate, DateTime EndDate)
{
this.Name = Name;
this.Number = Number;
this.User = User;
this.StartDate = StartDate;
this.EndDate = EndDate;
}
static int CompareTo(DataItem diOther)
{
int compareResult;
compareResult = Name.CompareTo(diOther.Name);
if (compareResult != 0)
{
goto Done;
}
compareResult = Number.CompareTo(diOther.Number);
if (compareResult != 0)
{
goto Done;
}
compareResult = User.CompareTo(diOther.User);
if (compareResult != 0)
{
goto Done;
}
compareResult = StartDate.CompareTo(diOther.StartDate);
if (compareResult != 0)
{
goto Done;
}
compareResult = EndDate.CompareTo(diOther.EndDate);
Done:
return compareResult;
}
}
Then you can write code like this:
void AddDataItem(SortedList list, DataItem di)
{
if (!list.ContainsKey(di))
{
// All we really care about is the key, so don't bother
// with a non-null value
list.Add(di, null);
}
}
Or, not doing any of the duplicate-removing work until the end (i.e. using
a List):
// Do this for each new data item
void AddDataItem(List list, DataItem di)
{
list.Add(di);
}
// Once you've got all the data, do this
void RemoveDuplicates(List list)
{
if (list.Count > 0)
{
list.Sort();
int idi = 1;
DataItem di = list[0];
while (idi < list.Count)
{
if (di.CompareTo(list[idi]) == 0)
{
list.RemoveAt(idi);
}
else
{
di = list[idi++];
}
}
}
}
Some notes:
* The above isn't optimized. For example, you could improve the
removal performance by going backwards. But you said you've only got
hundreds of elements, and they come from a web service, so it seems
unlikely you'd get enough of a performance improvement to make it worth
obufscating the code here.
* At least in the case of the List class, you can sort without the
elements implementing IComparable, as long as you provide a comparison
delegate at the time you do the sort. So strictly speaking you don't need
to implement IComparable for your data structure (the CompareTo() method
could just be passed directly to the Sort() method as the comparer
method). Since the code has to go _somewhere_ and since there are other
potential benefits to implementing IComparable, I prefer doing so. I
think that using the Sort() overloads that take comparers are more useful
for data types you don't have control over.
Pete |
|
| Back to top |
|
 |
Alun Harford
Joined: 08 Aug 2007 Posts: 9
|
Posted: Thu Dec 13, 2007 6:02 am Post subject: Re: not sure if there is an easy way to do this! |
|
|
Alun Harford wrote:
> Paul wrote:
>> Hi I have an array list in C# and I need to remove duplicates of data
>> groups in an array list. After the array list is populated each group
>> of data is 5 elements in order (0-4,5-9,10-14), name (string), number
>> (string), user(string), startdate(datetime), enddate(datetime). So it
>> might look like
>> arraylist[0]="truck";
>> arraylist[1]="242";
>> arraylist[2]="tom";
>> arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
>> arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
>> //start of next group
>> arraylist[5]="car";
>> When the array is filled it has several hundred values by reading data
>> from a webservice, but I only want to remove values when all 5
>> elements of each group matches another group so I am left with only
>> the unique groups.
>
> Using C# 3 here...
>
> Well you make your own data type. In this case, I'll make a struct
> (since I'm assuming this is pure data with no behavior attached - and
> because I'm to write the Equals() and GetHashCode() methods to make a
> complete example with a proper class).
>
> public struct MyType
> {
> public string Name { get; set; }
> public string Number /* Eugh! */ { get; set; }
> public string User { get; set; }
> public DateTime StartDate { get; set; }
> public DateTime EndDate { get; set; }
>
> public MyType(IList items, int startIndex) {
> Name = items[startIndex];
> Number = items[startIndex + 1];
> User = items[startIndex + 2];
> StartDate = items[startIndex + 3];
> EndDate = items[startIndex + 4];
> }
> }
>
> You can now make a method in another class:
>
> public List GetDistinctElements(IList items) {
> if(items==null) throw new ArgumentNullException("items");
> if(items.Count%5!=0) throw new ArgumentException("items.Count%5!=0");
>
> List result = new List();
> for(int i=0;i
> result.Add(new MyType(items, i));
> }
> return result.Distinct();
> }
Err... before Jon corrects me
The last line should be:
return result.Distinct().ToList();
Some people might get upset about this abuse of structs, and I guess I
agree with them - but it makes the code short for a newsgroup post.
Alun Harford |
|
| Back to top |
|
 |
carnold
Joined: 07 Dec 2007 Posts: 2
|
Posted: Thu Dec 13, 2007 12:11 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
On Dec 12, 5:50 pm, Paul wrote:
> Hi I have an array list in C# and I need to remove duplicates of data groups
> in an array list. After the array list is populated each group of data is 5
> elements in order (0-4,5-9,10-14), name (string), number (string),
> user(string), startdate(datetime), enddate(datetime). So it might look like
> arraylist[0]="truck";
> arraylist[1]="242";
> arraylist[2]="tom";
> arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
> arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
> //start of next group
> arraylist[5]="car";
> When the array is filled it has several hundred values by reading data from
> a webservice, but I only want to remove values when all 5 elements of each
> group matches another group so I am left with only the unique groups.
> Thanks Paul.
>
> --
> Paul G
> Software engineer.
FWIW, here's what it would look like in python:
assert len(arraylist) > 0 and len(arraylist) % 5 == 0, "arraylist
isn't setup right"
groupedList = zip(arraylist[0::5], arraylist[1::5], arraylist[2::5],
arraylist[3::5], arraylist[4::5])
uniqueGroupedList = set(groupedList) |
|
| Back to top |
|
 |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Thu Dec 13, 2007 1:06 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
thanks for the response. Probably do not have to use an array list but will
have to rewrite a small portion of the code. Array lists are convenient in
that they accept all datatypes!
--
Paul G
Software engineer.
"Peter Duniho" wrote:
> On Wed, 12 Dec 2007 15:50:02 -0800, Paul
> wrote:
>
> > Hi I have an array list in C# and I need to remove duplicates of data
> > groups
> > in an array list. After the array list is populated each group of data
> > is 5
> > elements in order (0-4,5-9,10-14), name (string), number (string),
> > user(string), startdate(datetime), enddate(datetime).
>
> I would say that this example is a great example of how _not_ to store
> your data, as well as an example of the hazards of using a type-agnostic
> data structure like ArrayList.
>
> I think it's a really bad idea to store data items in a collection in the
> way you've done it. For a variety of reasons, but mainly because a
> collection ought to have a direct mapping between a single data type and
> an element in the collection. There's no way to describe what your
> collection actually contains, because each element is different from 80%
> of the other elements.
>
> As far as your specific question goes...
>
> I would first suggest that you stop using an ArrayList like that. Create
> a new data structure that contains each of the data elements you're
> referencing, and then store that data structure in a collection. Then,
> make sure the new data structure implements IComparable, so that you can
> do things like sorting and comparing for equality.
>
> Then you can just store the data in a List, sorting the list after
> you've received all of the data and removing the duplicates with a linear
> scan through the list. Yet another alternative would be to use a
> SortedList, adding items only if they already aren't in the list. This
> avoids having to sort at the end, but of course you have the overhead of
> inserting elements as you go along.
>
> Alternatively, you can use a Dictionary containing your data, with the
> data structure itself being its own key. That provides a fast and
> convenient way to ensure that you only ever have one instance of any given
> group of data. You'd have to override the Object.GetHashCode() method for
> your new data structure though, basing your hash code on the data in the
> object.
>
> A dictionary would be faster than the sorted list, with the trade-off that
> it requires you also implement GetHashCode(), and of course you don't get
> a sorted list of data in the end (but that may not be needed anyway).
>
> If for some reason you _must_ have this data in an ArrayList that looks
> like what you've described, I would still do the above, but the convert
> the results back to an ArrayList as needed. You could either brute-force
> the problem by scanning the ArrayList considering five elements at a time
> (easy to write, but terrible performance), or manually sorting the list,
> again using five elements at a time for the sort (harder to write, but
> good performance). But the framework won't give you any help there, and
> while it's not hard to implement your own sort, it would be a pain
> (especially given the "five elements at a time" requirement that would
> lead you to have to do that in the first place) and certainly much more
> trouble than just creating a new structure that implements IComparable.
>
> If you have a data structure like this:
>
> struct DataItem : IComparable
> {
> readonly string Name;
> readonly int Number;
> readonly string User;
> readonly DateTime StartDate;
> readonly DateTime EndDate;
>
> public DataItem(string Name, int Number, string User, DateTime
> StartDate, DateTime EndDate)
> {
> this.Name = Name;
> this.Number = Number;
> this.User = User;
> this.StartDate = StartDate;
> this.EndDate = EndDate;
> }
>
> static int CompareTo(DataItem diOther)
> {
> int compareResult;
>
> compareResult = Name.CompareTo(diOther.Name);
> if (compareResult != 0)
> {
> goto Done;
> }
>
> compareResult = Number.CompareTo(diOther.Number);
> if (compareResult != 0)
> {
> goto Done;
> }
>
> compareResult = User.CompareTo(diOther.User);
> if (compareResult != 0)
> {
> goto Done;
> }
>
> compareResult = StartDate.CompareTo(diOther.StartDate);
> if (compareResult != 0)
> {
> goto Done;
> }
>
> compareResult = EndDate.CompareTo(diOther.EndDate);
> Done:
> return compareResult;
> }
> }
>
> Then you can write code like this:
>
> void AddDataItem(SortedList list, DataItem di)
> {
> if (!list.ContainsKey(di))
> {
> // All we really care about is the key, so don't bother
> // with a non-null value
> list.Add(di, null);
> }
> }
>
> Or, not doing any of the duplicate-removing work until the end (i.e. using
> a List):
>
> // Do this for each new data item
> void AddDataItem(List list, DataItem di)
> {
> list.Add(di);
> }
>
> // Once you've got all the data, do this
> void RemoveDuplicates(List list)
> {
> if (list.Count > 0)
> {
> list.Sort();
>
> int idi = 1;
> DataItem di = list[0];
>
> while (idi < list.Count)
> {
> if (di.CompareTo(list[idi]) == 0)
> {
> list.RemoveAt(idi);
> }
> else
> {
> di = list[idi++];
> }
> }
> }
> }
>
> Some notes:
>
> * The above isn't optimized. For example, you could improve the
> removal performance by going backwards. But you said you've only got
> hundreds of elements, and they come from a web service, so it seems
> unlikely you'd get enough of a performance improvement to make it worth
> obufscating the code here.
>
> * At least in the case of the List class, you can sort without the
> elements implementing IComparable, as long as you provide a comparison
> delegate at the time you do the sort. So strictly speaking you don't need
> to implement IComparable for your data structure (the CompareTo() method
> could just be passed directly to the Sort() method as the comparer
> method). Since the code has to go _somewhere_ and since there are other
> potential benefits to implementing IComparable, I prefer doing so. I
> think that using the Sort() overloads that take comparers are more useful
> for data types you don't have control over.
>
> Pete
> |
|
| Back to top |
|
 |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Thu Dec 13, 2007 1:08 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
thanks for the information! This is a great forum as I received a lot of
responses on this question!
--
Paul G
Software engineer.
"Jon Skeet [C# MVP]" wrote:
> Paul wrote:
> > Hi Jon, thanks for the information. Just wondering if you could provide a
> > brief example, I can convert all to the same type, but am not sure about
> > object encapsulating the name, number, user, start date and end date. I have
> > not worked with hash tables but I think I understand the general concept.
> > Hash table
> > key object
> > 1 (contains 5 grouped items)
>
> Something like (replace Foo with a useful name - I don't know what your
> groups really represent):
>
> public class Foo
> {
> readonly string name;
> readonly string number; // Misnomer?
> readonly string user;
> readonly DateTime startDate;
> readonly DateTime endDate;
>
> public Foo(string name, string number, string user,
> DateTime startDate, DateTime endDate)
> {
> this.name = name;
> this.number = number;
> this.user = user;
> this.startDate = startDate;
> this.endDate = endDate;
> }
>
> // Put properties supporting the variables in here
>
> public override bool Equals(object other)
> {
> Foo otherFoo = other as Foo;
> if (otherFoo==null)
> {
> return false;
> }
> return otherFoo.name==name &&
> otherFoo.number==number &&
> otherFoo.user==user &&
> otherFoo.startDate==startDate &&
> otherFoo.endDate==endDate;
> }
>
> public override int GetHashCode()
> {
> int hash = 17;
> hash = hash*23 + name.GetHashCode();
> hash = hash*23 + number.GetHashCode();
> hash = hash*23 + user.GetHashCode();
> hash = hash*23 + startDate.GetHashCode();
> hash = hash*23 + endDate.GetHashCode();
> return hash;
> }
> }
>
> To convert the list, you'd do something like:
>
> Hashtable grouped = new Hashtable();
> for (int i=0; i < original.Count/5; i++)
> {
> Foo foo = new Foo ((string)original[i*5],
> (string)original[i*5+1]
> (string)original[i*5+2]
> (DateTime)original[i*5+3]
> (DateTime)original[i*5+4]);
>
> grouped[foo] = foo;
> }
>
> Then use grouped.Keys to get at them.
>
> --
> Jon Skeet -
> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
> World class .NET training in the UK: http://iterativetraining.co.uk
> |
|
| Back to top |
|
 |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Thu Dec 13, 2007 1:26 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
thanks for the information, will give it a try!
--
Paul G
Software engineer.
"Alun Harford" wrote:
> Alun Harford wrote:
> > Paul wrote:
> >> Hi I have an array list in C# and I need to remove duplicates of data
> >> groups in an array list. After the array list is populated each group
> >> of data is 5 elements in order (0-4,5-9,10-14), name (string), number
> >> (string), user(string), startdate(datetime), enddate(datetime). So it
> >> might look like
> >> arraylist[0]="truck";
> >> arraylist[1]="242";
> >> arraylist[2]="tom";
> >> arraylist[3]=Convert.todatetime("12/10/2007 00:10:00");
> >> arraylist[4]=Convert.todatetime("12/11/2007 00:10:00");
> >> //start of next group
> >> arraylist[5]="car";
> >> When the array is filled it has several hundred values by reading data
> >> from a webservice, but I only want to remove values when all 5
> >> elements of each group matches another group so I am left with only
> >> the unique groups.
> >
> > Using C# 3 here...
> >
> > Well you make your own data type. In this case, I'll make a struct
> > (since I'm assuming this is pure data with no behavior attached - and
> > because I'm to write the Equals() and GetHashCode() methods to make a
> > complete example with a proper class).
> >
> > public struct MyType
> > {
> > public string Name { get; set; }
> > public string Number /* Eugh! */ { get; set; }
> > public string User { get; set; }
> > public DateTime StartDate { get; set; }
> > public DateTime EndDate { get; set; }
> >
> > public MyType(IList items, int startIndex) {
> > Name = items[startIndex];
> > Number = items[startIndex + 1];
> > User = items[startIndex + 2];
> > StartDate = items[startIndex + 3];
> > EndDate = items[startIndex + 4];
> > }
> > }
> >
> > You can now make a method in another class:
> >
> > public List GetDistinctElements(IList items) {
> > if(items==null) throw new ArgumentNullException("items");
> > if(items.Count%5!=0) throw new ArgumentException("items.Count%5!=0");
> >
> > List result = new List();
> > for(int i=0;i
> > result.Add(new MyType(items, i));
> > }
> > return result.Distinct();
> > }
>
> Err... before Jon corrects me
>
> The last line should be:
>
> return result.Distinct().ToList();
>
>
> Some people might get upset about this abuse of structs, and I guess I
> agree with them - but it makes the code short for a newsgroup post.
>
> Alun Harford
> |
|
| Back to top |
|
 |
Paul
Joined: 08 Aug 2007 Posts: 19
|
Posted: Thu Dec 13, 2007 2:36 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
Hi Joh, I implimented your code since it looked quick, seems to work! Anyhow
just trying to understand it but for the public override int GetHashCode()
why is it hash = hash*23+name.GetHashCode(); and int has =17, is this a size?
I still need to get at the data so will use the grouped.Keys as you stated.
thanks
--
Paul G
Software engineer.
"Jon Skeet [C# MVP]" wrote:
> Paul wrote:
> > Hi Jon, thanks for the information. Just wondering if you could provide a
> > brief example, I can convert all to the same type, but am not sure about
> > object encapsulating the name, number, user, start date and end date. I have
> > not worked with hash tables but I think I understand the general concept.
> > Hash table
> > key object
> > 1 (contains 5 grouped items)
>
> Something like (replace Foo with a useful name - I don't know what your
> groups really represent):
>
> public class Foo
> {
> readonly string name;
> readonly string number; // Misnomer?
> readonly string user;
> readonly DateTime startDate;
> readonly DateTime endDate;
>
> public Foo(string name, string number, string user,
> DateTime startDate, DateTime endDate)
> {
> this.name = name;
> this.number = number;
> this.user = user;
> this.startDate = startDate;
> this.endDate = endDate;
> }
>
> // Put properties supporting the variables in here
>
> public override bool Equals(object other)
> {
> Foo otherFoo = other as Foo;
> if (otherFoo==null)
> {
> return false;
> }
> return otherFoo.name==name &&
> otherFoo.number==number &&
> otherFoo.user==user &&
> otherFoo.startDate==startDate &&
> otherFoo.endDate==endDate;
> }
>
> public override int GetHashCode()
> {
> int hash = 17;
> hash = hash*23 + name.GetHashCode();
> hash = hash*23 + number.GetHashCode();
> hash = hash*23 + user.GetHashCode();
> hash = hash*23 + startDate.GetHashCode();
> hash = hash*23 + endDate.GetHashCode();
> return hash;
> }
> }
>
> To convert the list, you'd do something like:
>
> Hashtable grouped = new Hashtable();
> for (int i=0; i < original.Count/5; i++)
> {
> Foo foo = new Foo ((string)original[i*5],
> (string)original[i*5+1]
> (string)original[i*5+2]
> (DateTime)original[i*5+3]
> (DateTime)original[i*5+4]);
>
> grouped[foo] = foo;
> }
>
> Then use grouped.Keys to get at them.
>
> --
> Jon Skeet -
> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
> World class .NET training in the UK: http://iterativetraining.co.uk
> |
|
| Back to top |
|
 |
Jon Skeet [C# MVP]
Joined: 08 Aug 2007 Posts: 266
|
Posted: Thu Dec 13, 2007 10:47 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
Paul wrote:
> Hi Joh, I implimented your code since it looked quick, seems to work! Anyhow
> just trying to understand it but for the public override int GetHashCode()
> why is it hash = hash*23+name.GetHashCode(); and int has =17, is this a size?
> I still need to get at the data so will use the grouped.Keys as you stated.
The 17 is just an initial value. This is the way I normally do
hashcodes, as suggested by Josh Bloch's excellent book "Effective
Java".
--
Jon Skeet -
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk |
|
| Back to top |
|
 |
Peter Duniho
Joined: 08 Aug 2007 Posts: 45
|
Posted: Thu Dec 13, 2007 2:51 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
On Thu, 13 Dec 2007 09:36:00 -0800, Paul
wrote:
> Hi Joh, I implimented your code since it looked quick, seems to work!
> Anyhow
> just trying to understand it but for the public override int
> GetHashCode()
> why is it hash = hash*23+name.GetHashCode(); and int has =17, is this a
> size?
Those are just prime numbers to help make a reliable hash code out of each
member's own hash code.
I don't know if Jon picked them because he just happens to like those
particular prime numbers (I'm a big fan of 17 myself), or if he knows
something about the .NET implementations of GetHashCode() for the various
types that makes those numbers more useful than others. But to some
extent, they are just "magic numbers".
Pete |
|
| Back to top |
|
 |
Peter Duniho
Joined: 08 Aug 2007 Posts: 45
|
Posted: Thu Dec 13, 2007 2:51 pm Post subject: Re: not sure if there is an easy way to do this! |
|
|
On Thu, 13 Dec 2007 08:06:02 -0800, Paul
wrote:
> thanks for the response. Probably do not have to use an array list but
> will
> have to rewrite a small portion of the code. Array lists are convenient
> in
> that they accept all datatypes!
Yes, but that's the sort of convenience that's only convenient until it's
trouble. 
|
|
| Back to top |
|
 |
|
|
| Related Topics: | Possible easy caching But I'm a bit confused. I've read all about the Caching in patterns and practices, but somehow I dont quite get it. I need a way to Cache a DataTable, the DataTable is located in my businesslayer - and I want to share that DataTable between multiple reque
easy question ? I have a VS setup project to install a webservice. Works fine. Except that I want a file dbalias.xml to have permissions for everybody to write. Currently I have to do this manually after installation. Whats the best way to do this ? Thanks Chris Brooksba
Hopefully an easy question Hi All, I am new to VB.Net but i am pretty experienced with MS Access. I have VB.Net & SQL Express. I have set up two tables in SQL Server Express and have got them to show up fine on my VB.net form, now i wish to have a dynamic field which is the sum of
Easy SOAP Payload encryption What is the easiest way to encrypt a SOAP message? I thought i saw an episode of "The .NET Show" that showed this, but I cannot find it. They created a SOAP handler and it took care fo everything. Any help is appreciated. Thanks Scott
Looking for an easy way to interrogate a file on my Pocket P I want to interrogate an xml file stored on my Pocket PC from a desktop app written in VB.Net. So far the only ways I have seen to do this are : - to manually copy the file to my desktop using activesync and then interrogate it or - install IIS on my desk |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|