Solved

Need help comparing 2 arraylists.

Posted on 2014-12-19
2
56 Views
Last Modified: 2015-10-10
Hi, I am looking for a code sample to help with the following situation.

Widget - Custom class with a color property.
DoSomething - Function that takes 2 widgets as arguments and returns a Widget.

I need to compare two arraylists against each other element by element.  Both arraylists consist of Widgets with a string "+" in between each Widget and they (the arraylists) may be of different lengths.  For example:
•      ArrLst1 would contain {a+b+c}
•      ArrLst2 would contain {a+c+d+e}
The results of the comparison will be held in a third arraylist called SumArr.
When comparing the arraylists:
•      If the elements being compared are both Widgets and:
o      They have the same color value.  Perform the DoSomething function on both Widgets and add the returned widget to SumArr.  For display purposes the returned Widget will be represented as [ArrLst1(element),ArrLst2(element)].
o      They have different color values.  Add the widget from ArrLst1 to SumArr.
•      After a widget has been added to SumArr:
o      Automatically add a “+” to SumArr.
o      That widget can no longer be used in future comparisons (in either ArrLst1 or ArrLst2).  This is where my problem really happens.  I cannot find a way to not include, skip over or remove the elements from the arraylists after I have used them and not cause an error for changing the arraylist.
This should cause all of the Widgets in ArrLst1 to be added to SumArr.  If there are any leftover Widgets in ArrLst2 after the comparison has been completed they should be added to the end of SumArr with a string "+" in between each Widget.  Using the previous examples for ArrLst1 and ArrLst2, The final contents of SumArr would be {[a,a],+,b,+,[c,c],+,d,+,e}.

Here is the code that I have been trying to get to work:
    Sub Main()
        Dim ArrLst1 As New ArrayList
        Dim ArrLst2 As New ArrayList
        Dim SumArr As New ArrayList
        Dim ExitA As Boolean
        Dim T1 As Integer
        Dim T2 As Integer

        ArrLst1.AddRange("a,+,b,+,c".Split(","))
        ArrLst2.AddRange("a,+,c,+,d,+,e".Split(","))

        While ArrLst1.Count > 0 And ExitA = False
            While T2 <= ArrLst2.Count - 1 And ExitA = False
                If ArrLst1(T1).Equals(ArrLst2(T2)) Then
                    If ArrLst1(T1) <> "+" Then
                        SumArr.Add(DoSomething(ArrLst1(T1), ArrLst2(T2)))
                    Else
                        SumArr.Add(ArrLst1(T1))
                    End If
                    ArrLst1.Remove(ArrLst1(T1))
                    ArrLst2.Remove(ArrLst1(T2))
                    ExitA = True
                Else
                    SumArr.Add(ArrLst1(T1))
                    ArrLst1.Remove(ArrLst1(T1))
                End If
                T2 += 1
            End While
            T1 += 1
            ExitA = False
        End While

        SumArr.AddRange(ArrLst2)

        For Each item As String In SumArr
            Console.Write(item)
        Next

        Console.ReadLine()

Open in new window


Once I complete my final solution I do intend to change from arraylists to something else, so if you have any thoughts on what would be the best collection to use I'm all ears.
0
Comment
Question by:NevSoFly
2 Comments
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 250 total points
Comment Utility
Why have the "+" in the ArrayList at all?...that's kinda weird to me.

Anyways, try this out:
Public Class Widget

    Public Color As String

    Public Sub New(ByVal C As String)
        Me.Color = C
    End Sub

    Public Overrides Function ToString() As String
        Return Color
    End Function

    Public Overrides Function Equals(obj As Object) As Boolean
        Return Me.Color.Equals(DirectCast(obj, Widget).Color)
    End Function

End Class

Module Module1

    Sub Main()
        Dim ArrLst1 As New ArrayList
        Dim ArrLst2 As New ArrayList
        Dim SumArr As New ArrayList

        ' Create the weird mix of Widget instances and String "+":
        For Each c As String In "a,+,b,+,c".Split(",")
            If c <> "+" Then
                ArrLst1.Add(New Widget(c))
            Else
                ArrLst1.Add(c)
            End If
        Next
        For Each c As String In "a,+,c,+,d,+,e".Split(",")
            If c <> "+" Then
                ArrLst2.Add(New Widget(c))
            Else
                ArrLst2.Add(c)
            End If
        Next

        ' Make a COPY of ArrLst2 so we can remove things from it without destroying the original list:
        Dim ArrLst2Copy As New ArrayList(ArrLst2)

        ' Do the comparisons, building SumArr as we go:
        For Each obj As Object In ArrLst1
            If TypeOf obj Is Widget Then
                Dim W1 As Widget = DirectCast(obj, Widget)
                For i As Integer = 0 To ArrLst2Copy.Count - 1
                    If TypeOf ArrLst2Copy(i) Is Widget Then
                        Dim W2 As Widget = DirectCast(ArrLst2Copy(i), Widget)
                        If W1.Equals(W2) Then
                            SumArr.Add(DoSomething(W1, W2))
                            ArrLst2Copy.Remove(W2)
                        Else
                            SumArr.Add(W1)
                        End If
                        SumArr.Add("+")
                        Exit For
                    End If
                Next
            End If
        Next

        ' Add what is left over in ArrLst2Copy
        For Each obj As Object In ArrLst2Copy
            If TypeOf obj Is Widget Then
                SumArr.Add(obj)
                SumArr.Add("+")
            End If
        Next

        ' Remove the trailing "+"
        If SumArr.Count > 0 Then
            SumArr.RemoveAt(SumArr.Count - 1)
        End If

        ' See what the result is:
        For Each obj As Object In SumArr
            Console.Write(obj.ToString)
        Next
        Console.ReadLine()
    End Sub

    Public Function DoSomething(ByVal W1 As Widget, ByVal W2 As Widget) As Widget
        Return New Widget("[" & W1.ToString & "," & W2.ToString & "]")
    End Function

End Module

Open in new window

0
 
LVL 32

Assisted Solution

by:it_saige
it_saige earned 250 total points
Comment Utility
I was thinking the same thing Mike.  Here is an example using a List(Of Widget) implementation:
Imports System.Drawing
Imports System.Linq

Module Module1
	Private widgets1 As New Widgets() From _
	 { _
	  New Widget() With {.ID = 0, .Letter = "a", .Color = Color.Blue}, _
	  New Widget() With {.ID = 1, .Letter = "b", .Color = Color.Green}, _
	  New Widget() With {.ID = 2, .Letter = "c", .Color = Color.Orange} _
	 }

	Private widgets2 As New Widgets() From _
	 { _
	  New Widget() With {.ID = 5, .Letter = "a", .Color = Color.Blue}, _
	  New Widget() With {.ID = 6, .Letter = "c", .Color = Color.Orange}, _
	  New Widget() With {.ID = 7, .Letter = "d", .Color = Color.White}, _
	  New Widget() With {.ID = 8, .Letter = "e", .Color = Color.Purple} _
	 }

	Sub Main()
		Dim sumArr = New Widgets()
		sumArr.Combine(widgets1, widgets2)
		Console.WriteLine(sumArr)
		sumArr.FullDetails()
		Console.ReadLine()
	End Sub
End Module

Class Widgets
	Implements IList(Of Widget)
	Private ReadOnly fInnerList As IList(Of Widget)

	Public Sub New()
		MyBase.New()
		fInnerList = New List(Of Widget)
	End Sub

	Public Sub New(ByVal widgets As IEnumerable(Of Widget))
		Me.New()
		AddRange(widgets)
	End Sub

	Public Sub Add(ByVal item As Widget) Implements ICollection(Of Widget).Add
		If Not item Is Nothing Then fInnerList.Add(item)
	End Sub

	Public Sub AddRange(ByVal widgets As IEnumerable(Of Widget))
		For Each widget As Widget In widgets
			Add(widget)
		Next
	End Sub

	Public Sub Clear() Implements ICollection(Of Widget).Clear
		fInnerList.Clear()
	End Sub

	Public Sub Combine(ByVal widgets As IEnumerable(Of Widget))
		AddRange(widgets)
	End Sub

	Public Sub Combine(ByVal widgets1 As IEnumerable(Of Widget), ByVal widgets2 As IEnumerable(Of Widget))
		Dim sameColor = (From w2 In widgets2 Where widgets1.Contains(w2, New WidgetEqualityComparer()) Select widgets1.Combine(w2))
		AddRange(sameColor)
		AddRange(widgets1.Except(sameColor, New WidgetEqualityComparer()))
		AddRange(widgets2.Except(sameColor, New WidgetEqualityComparer()))
	End Sub

	Public Function Contains(ByVal item As Widget) As Boolean Implements ICollection(Of Widget).Contains
		Return fInnerList.Contains(item)
	End Function

	Public Sub CopyTo(ByVal array() As Widget, ByVal arrayIndex As Integer) Implements ICollection(Of Widget).CopyTo
		Dim tempList As New List(Of Widget)
		tempList.AddRange(fInnerList)
		tempList.CopyTo(array, arrayIndex)
	End Sub

	Public ReadOnly Property Count As Integer Implements ICollection(Of Widget).Count
		Get
			Return fInnerList.Count
		End Get
	End Property

	Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of Widget).IsReadOnly
		Get
			Return False
		End Get
	End Property

	Public Function Remove(ByVal item As Widget) As Boolean Implements ICollection(Of Widget).Remove
		Return If(Not item Is Nothing, fInnerList.Remove(item), False)
	End Function

	Public Function GetEnumerator() As IEnumerator(Of Widget) Implements IEnumerable(Of Widget).GetEnumerator
		Return New GenericEnumerator(Of Widget)(fInnerList)
	End Function

	Public Function IndexOf(ByVal item As Widget) As Integer Implements IList(Of Widget).IndexOf
		Return If(Not item Is Nothing, fInnerList.IndexOf(item), -1)
	End Function

	Public Sub Insert(ByVal index As Integer, ByVal item As Widget) Implements IList(Of Widget).Insert
		If Not item Is Nothing Then fInnerList.Insert(index, item)
	End Sub

	Default Public Property Item(ByVal index As Integer) As Widget Implements IList(Of Widget).Item
		Get
			Return fInnerList(index)
		End Get
		Set(ByVal value As Widget)
			If Not fInnerList.Contains(value) Then
				Dim widget As New Widget()
				fInnerList(index) = widget
			End If
		End Set
	End Property

	Public Sub RemoveAt(ByVal index As Integer) Implements IList(Of Widget).RemoveAt
		fInnerList.RemoveAt(index)
	End Sub

	Public Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
		Return GetEnumerator()
	End Function

	Public Function FullDetails()
		Console.WriteLine("Full Details for the InnerList - {0}", ToString())
		For Each widget In fInnerList
			Console.WriteLine(widget)
		Next
	End Function

	Public Overrides Function ToString() As String
		Dim result As String = String.Empty
		For Each widget In fInnerList
			result = If(fInnerList.IndexOf(widget) = 0, String.Format("{0}", widget.Letter), String.Format("{0}+{1}", result, widget.Letter))
		Next
		Return result
	End Function
End Class

Class Widget
	Public Property ID() As Integer
	Public Property Letter() As Char
	Public Property Color() As Color
	Public ReadOnly Property Name() As String
		Get
			Return Color.Name
		End Get
	End Property

#Region "Overriden Methods"
	Public Overrides Function ToString() As String
		Return String.Format("{0}: {1}{2}", Letter, Name, ID)
	End Function

	Public Overrides Function Equals(ByVal obj As Object) As Boolean
		If obj Is Nothing OrElse (obj.[GetType]() IsNot [GetType]()) Then
			Return False
		End If

		Return Me Is TryCast(obj, Widget)
	End Function

	Public Overloads Function Equals(ByVal widget As Widget) As Boolean
		If Object.ReferenceEquals(widget, Nothing) Then
			Return False
		End If

		Return Me Is widget
	End Function

	Public Overrides Function GetHashCode() As Integer
		Return HashHelper.GetHashCode(ID, Letter, Color, Name)
	End Function
#End Region

#Region "Operator Overloads"
	Public Shared Operator =(ByVal lhs As Widget, ByVal rhs As Widget) As Boolean
		If Object.ReferenceEquals(lhs, rhs) Then
			Return True
		End If

		If Object.ReferenceEquals(lhs, Nothing) OrElse Object.ReferenceEquals(rhs, Nothing) Then
			Return False
		End If

		Return (lhs.ID.Equals(rhs.ID) AndAlso lhs.Letter.Equals(rhs.Letter) AndAlso lhs.Color.Equals(rhs.Color) AndAlso (If(lhs.Name IsNot Nothing AndAlso rhs.Name IsNot Nothing, lhs.Name.Equals(rhs.Name), False)))
	End Operator

	Public Shared Operator <>(ByVal lhs As Widget, ByVal rhs As Widget) As Boolean
		Return Not (lhs = rhs)
	End Operator
#End Region
End Class

Class WidgetEqualityComparer
	Inherits EqualityComparer(Of Widget)

	Public Overrides Function Equals(ByVal widget1 As Widget, ByVal widget2 As Widget) As Boolean
		If Object.ReferenceEquals(widget1, Nothing) OrElse Object.ReferenceEquals(widget2, Nothing) Then
			Return False
		End If

		Return widget1.Color.Equals(widget2.Color)
	End Function

	Public Overrides Function GetHashCode(ByVal widget As Widget) As Integer
		Return HashHelper.GetHashCode(widget)
	End Function
End Class

Module Extensions
	<System.Runtime.CompilerServices.Extension()> _
	Public Function Combine(ByVal source As IEnumerable(Of Widget), ByVal widget As Widget) As Widget
		Return (From w1 In source Where w1.Color.Equals(widget.Color) Select New Widget() With {.ID = w1.ID + widget.ID, .Letter = w1.Letter, .Color = w1.Color}).FirstOrDefault()
	End Function
End Module

NotInheritable Class HashHelper
	Public Overloads Shared Function GetHashCode(Of T1, T2)(ByVal arg1 As T1, ByVal arg2 As T2) As Integer
		Return GetHashCode(New Object() {arg1, arg2})
	End Function

	Public Overloads Shared Function GetHashCode(Of T1, T2, T3)(ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3) As Integer
		Return GetHashCode(New Object() {arg1, arg2, arg3})
	End Function

	Public Overloads Shared Function GetHashCode(Of T1, T2, T3, T4)(ByVal arg1 As T1, ByVal arg2 As T2, ByVal arg3 As T3, ByVal arg4 As T4) As Integer
		Return GetHashCode(New Object() {arg1, arg2, arg3, arg4})
	End Function

	Public Overloads Shared Function GetHashCode(ByVal ParamArray args As Object()) As Integer
		Dim hash As Integer = 0
		For Each item As Object In args
			hash = 31 Or hash + (If((item IsNot Nothing), item.GetHashCode(), 0))
		Next
		Return hash

	End Function
End Class

Class GenericEnumerator(Of T)
	Implements IEnumerator(Of T)

	Private fCollection As IEnumerable(Of T)
	Private fPosition As Integer
	Private fMax As Integer

	Public Sub New(ByVal collection As IEnumerable(Of T))
		fCollection = collection
		fPosition = -1
		fMax = fCollection.Count - 1
	End Sub

	Public ReadOnly Property Current As T Implements IEnumerator(Of T).Current
		Get
			Return fCollection.ElementAt(fPosition)
		End Get
	End Property

	Public ReadOnly Property Current1 As Object Implements IEnumerator.Current
		Get
			Return Current
		End Get
	End Property

	Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
		If fPosition < fMax Then
			fPosition += 1
			Return True
		End If
		Return False
	End Function

	Public Sub Reset() Implements IEnumerator.Reset
		Throw New NotImplementedException()
	End Sub

#Region "IDisposable Support"
	Private disposedValue As Boolean ' To detect redundant calls

	' IDisposable
	Protected Overridable Sub Dispose(ByVal disposing As Boolean)
		If Not disposedValue Then
			If disposing Then
				' TODO: dispose managed state (managed objects).
			End If

			' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
			' TODO: set large fields to null.
		End If
		Me.disposedValue = True
	End Sub

	' This code added by Visual Basic to correctly implement the disposable pattern.
	Public Sub Dispose() Implements IDisposable.Dispose
		' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
		Dispose(True)
		GC.SuppressFinalize(Me)
	End Sub
#End Region
End Class

Open in new window


Produces the following output -Capture.JPG
-saige-
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
This video discusses moving either the default database or any database to a new volume.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now