D
Doug
I have another question that has to deal with the methods that the
Generic List object provides that require delegates but the delegates
do not allow you to pass in parameters. I'll explain first and then
try to provide an example.
I have an object that I put into the generic list, with a set of data
like below. I need to loop through this data and identify duplicates
(these have been grouped together because they are at a detail level
and at the header level they've been identified as "potential"
duplicates.) If the Destination, Origin, Mileage and Rate match for a
given LocationRateId and LocationRateSequence to at least one other
given LocationRateId and LocationRateSequence then it's a duplicate.
But if for another LocationRateSequence for that same LocationRateId,
there is no match to the LocationRateId and LocationRateSequence that
was matched earlier, then both rows are not considered duplicates and
both are scrapped (yes, I know this sounds confusing).
LocationRateId LocationRateSequence
Destination Origin
Mileage Rate
12345
1
678 901
100 5.50
12345
2
901 678
100 5.50
67890
1
123 456
95 6.00
67890
2
456 123
95 6.00
99990
1
123 456
95 6.00
99990
2
456 123
95 6.00
55555
1
678 901
100 5.50
55555
2
901 678
100 5.50
88888
1
678 901
100 5.50
88888
2
888 777
150 9.50
If you were to look at this data, LocationRateId 12345 is a duplicate
of 55555 and LocationRateId 67890 is a duplicate of 99990.
LocationRateId 88888 is not a match, because even though
LocationRateSequence 1 for that LocationRateId matches LocationRateId
12345 for it's LocationRateSequence 1, the two don't match for
LocationRateSequence of 2.
Ok, I would like to use the ForEach method in the GenericList object
to do this comparison. But I can't figure out how, because it takes a
delegate that takes no parameters. In order to do this, I would need
to have the overall Generic List passed into the method as well, to
compare with the one object that I'm looking at.
So, here's what I'm doing now, but I'm assuming this is not the best
option performance wise (it sure seems slow)...
Note, I'm including the code for my object, but am not including the
code for getting it filled and put into a generic list...
public class LocationRateDetail
{
private bool _markedForDeletion = false;
private decimal _legCost = decimal.MinValue;
private int _distance = int.MinValue;
private int _legSequenceNumber = int.MinValue;
private int _locationRatesId = int.MinValue;
private string _destinationLocationId = string.Empty;
private string _originLocationId = string.Empty;
public LocationRateDetail()
{ }
public LocationRateDetail(decimal legCost, int distance, int
legSequenceNumber, int locationRatesId, string destinationLocationId,
string originCustomerLocationId,
string originLocationId)
{
_legCost = legCost;
_distance = distance;
_legSequenceNumber = legSequenceNumber;
_locationRatesId = locationRatesId;
_destinationLocationId = destinationLocationId;
_originLocationId = originLocationId;
}
public bool MarkedForDeletion
{
get
{
return _markedForDeletion;
}
set
{
_markedForDeletion = value;
}
}
public decimal LegCost
{
get
{
return _legCost;
}
}
public int Distance
{
get
{
return _distance;
}
}
public int LegSequenceNumber
{
get
{
return _legSequenceNumber;
}
}
public int LocationRatesId
{
get
{
return _locationRatesId;
}
}
public string DestinationLocationId
{
get
{
return _destinationLocationId;
}
}
public string OriginLocationId
{
get
{
return _originLocationId;
}
}
}
Once my generic list has been filled with data, this is the method I
use to try to filter out not duplicates.
public static List<LocationRateDetail>
FilterOutNonDuplicates(List<LocationRateDetail> details)
{
bool keepChecking = true;
int numberDeleted = 0;
LocationRateDetail currentDetail = null;
string locationRatesToDelete = string.Empty;
while (keepChecking == true)
{
numberDeleted = 0;
for (int index = 0; index < details.Count; index++)
{
currentDetail = details[index];
if (currentDetail.MarkedForDeletion == false)
{
if
(locationRatesToDelete.IndexOf(currentDetail.LocationRatesId + ",") >=
0)
{
currentDetail.MarkedForDeletion = true;
}
else
{
if (CheckForDuplicate(currentDetail, details)
== false)
{
currentDetail.MarkedForDeletion = true;
locationRatesToDelete +=
currentDetail.LocationRatesId + ",";
numberDeleted++;
}
}
}
}
if ((numberDeleted == 0) ||
(details.Find(FindUnmarkedRate) == null))
{
keepChecking = false;
}
}
details.RemoveAll(FindMarkedRate);
return details;
}
private static bool FindUnmarkedRate(LocationRateDetail detail)
{
return !detail.MarkedForDeletion;
}
private static bool FindMarkedRate(LocationRateDetail detail)
{
return detail.MarkedForDeletion;
}
private static bool CheckForDuplicate(LocationRateDetail
currentDetail, List<LocationRateDetail> details)
{
bool foundDuplicate = false;
bool stopChecking = true;
LocationRateDetail detail = null;
for (int index = 0; index < details.Count; index++)
{
detail = details[index];
//Don't check any further if this is the same detail as the
current detail.
stopChecking = detail.Equals(currentDetail);
if ((stopChecking == false) &&
(CompareProperties(currentDetail, detail)))
{
foundDuplicate = true;
break;
}
}
return foundDuplicate;
}
private static bool CompareProperties(LocationRateDetail
currentDetail, LocationRateDetail detailToCheck)
{
bool propertiesMatch = false;
if ((currentDetail.LegSequenceNumber ==
detailToCheck.LegSequenceNumber) &&
(currentDetail.OriginLocationId.Trim() ==
detailToCheck.OriginLocationId.Trim()) &&
(currentDetail.DestinationLocationId.Trim() ==
detailToCheck.DestinationLocationId.Trim()) &&
(currentDetail.Distance == detailToCheck.Distance) &&
(currentDetail.LegCost == detailToCheck.LegCost))
{
propertiesMatch = true;
}
return propertiesMatch;
}
Generic List object provides that require delegates but the delegates
do not allow you to pass in parameters. I'll explain first and then
try to provide an example.
I have an object that I put into the generic list, with a set of data
like below. I need to loop through this data and identify duplicates
(these have been grouped together because they are at a detail level
and at the header level they've been identified as "potential"
duplicates.) If the Destination, Origin, Mileage and Rate match for a
given LocationRateId and LocationRateSequence to at least one other
given LocationRateId and LocationRateSequence then it's a duplicate.
But if for another LocationRateSequence for that same LocationRateId,
there is no match to the LocationRateId and LocationRateSequence that
was matched earlier, then both rows are not considered duplicates and
both are scrapped (yes, I know this sounds confusing).
LocationRateId LocationRateSequence
Destination Origin
Mileage Rate
12345
1
678 901
100 5.50
12345
2
901 678
100 5.50
67890
1
123 456
95 6.00
67890
2
456 123
95 6.00
99990
1
123 456
95 6.00
99990
2
456 123
95 6.00
55555
1
678 901
100 5.50
55555
2
901 678
100 5.50
88888
1
678 901
100 5.50
88888
2
888 777
150 9.50
If you were to look at this data, LocationRateId 12345 is a duplicate
of 55555 and LocationRateId 67890 is a duplicate of 99990.
LocationRateId 88888 is not a match, because even though
LocationRateSequence 1 for that LocationRateId matches LocationRateId
12345 for it's LocationRateSequence 1, the two don't match for
LocationRateSequence of 2.
Ok, I would like to use the ForEach method in the GenericList object
to do this comparison. But I can't figure out how, because it takes a
delegate that takes no parameters. In order to do this, I would need
to have the overall Generic List passed into the method as well, to
compare with the one object that I'm looking at.
So, here's what I'm doing now, but I'm assuming this is not the best
option performance wise (it sure seems slow)...
Note, I'm including the code for my object, but am not including the
code for getting it filled and put into a generic list...
public class LocationRateDetail
{
private bool _markedForDeletion = false;
private decimal _legCost = decimal.MinValue;
private int _distance = int.MinValue;
private int _legSequenceNumber = int.MinValue;
private int _locationRatesId = int.MinValue;
private string _destinationLocationId = string.Empty;
private string _originLocationId = string.Empty;
public LocationRateDetail()
{ }
public LocationRateDetail(decimal legCost, int distance, int
legSequenceNumber, int locationRatesId, string destinationLocationId,
string originCustomerLocationId,
string originLocationId)
{
_legCost = legCost;
_distance = distance;
_legSequenceNumber = legSequenceNumber;
_locationRatesId = locationRatesId;
_destinationLocationId = destinationLocationId;
_originLocationId = originLocationId;
}
public bool MarkedForDeletion
{
get
{
return _markedForDeletion;
}
set
{
_markedForDeletion = value;
}
}
public decimal LegCost
{
get
{
return _legCost;
}
}
public int Distance
{
get
{
return _distance;
}
}
public int LegSequenceNumber
{
get
{
return _legSequenceNumber;
}
}
public int LocationRatesId
{
get
{
return _locationRatesId;
}
}
public string DestinationLocationId
{
get
{
return _destinationLocationId;
}
}
public string OriginLocationId
{
get
{
return _originLocationId;
}
}
}
Once my generic list has been filled with data, this is the method I
use to try to filter out not duplicates.
public static List<LocationRateDetail>
FilterOutNonDuplicates(List<LocationRateDetail> details)
{
bool keepChecking = true;
int numberDeleted = 0;
LocationRateDetail currentDetail = null;
string locationRatesToDelete = string.Empty;
while (keepChecking == true)
{
numberDeleted = 0;
for (int index = 0; index < details.Count; index++)
{
currentDetail = details[index];
if (currentDetail.MarkedForDeletion == false)
{
if
(locationRatesToDelete.IndexOf(currentDetail.LocationRatesId + ",") >=
0)
{
currentDetail.MarkedForDeletion = true;
}
else
{
if (CheckForDuplicate(currentDetail, details)
== false)
{
currentDetail.MarkedForDeletion = true;
locationRatesToDelete +=
currentDetail.LocationRatesId + ",";
numberDeleted++;
}
}
}
}
if ((numberDeleted == 0) ||
(details.Find(FindUnmarkedRate) == null))
{
keepChecking = false;
}
}
details.RemoveAll(FindMarkedRate);
return details;
}
private static bool FindUnmarkedRate(LocationRateDetail detail)
{
return !detail.MarkedForDeletion;
}
private static bool FindMarkedRate(LocationRateDetail detail)
{
return detail.MarkedForDeletion;
}
private static bool CheckForDuplicate(LocationRateDetail
currentDetail, List<LocationRateDetail> details)
{
bool foundDuplicate = false;
bool stopChecking = true;
LocationRateDetail detail = null;
for (int index = 0; index < details.Count; index++)
{
detail = details[index];
//Don't check any further if this is the same detail as the
current detail.
stopChecking = detail.Equals(currentDetail);
if ((stopChecking == false) &&
(CompareProperties(currentDetail, detail)))
{
foundDuplicate = true;
break;
}
}
return foundDuplicate;
}
private static bool CompareProperties(LocationRateDetail
currentDetail, LocationRateDetail detailToCheck)
{
bool propertiesMatch = false;
if ((currentDetail.LegSequenceNumber ==
detailToCheck.LegSequenceNumber) &&
(currentDetail.OriginLocationId.Trim() ==
detailToCheck.OriginLocationId.Trim()) &&
(currentDetail.DestinationLocationId.Trim() ==
detailToCheck.DestinationLocationId.Trim()) &&
(currentDetail.Distance == detailToCheck.Distance) &&
(currentDetail.LegCost == detailToCheck.LegCost))
{
propertiesMatch = true;
}
return propertiesMatch;
}