Removing duplicates from an array

Hello,
I have this code…

//Remove the duplicate email addresses only
Dim z as integer
TheEmailAddressOnlyString = Trim(TheEmailAddressOnlyString)

Dim myArray() As String
myArray() = Split(TheEmailAddressOnlyString, Chr(13))
'msgbox Str(ubound(myArray()))

dim first_array() As string = myArray()
dim second_array(-1) As string

for i as integer = 0 to ubound(first_array())
  if second_array().indexof(first_array(i)) < 0 then
    second_array().append(first_array(i))
    Z = Z + 1
  end if
next

TheEmailAddressOnly = join(second_array, Chr(13))
TheEmailAddressOnly = Trim(TheEmailAddressOnly)

ListOfEmailAddressesWindow.TextArea3.Text = ""
ListOfEmailAddressesWindow.TextArea3.Text = TheEmailAddressOnly

If Z = 1 then
  ListOfEmailAddressesWindow.StaticText2.Text = "There is only one unique email address"
else
  ListOfEmailAddressesWindow.StaticText3.Text = "There are " + Str(Z) + " unique email addresses"
end if

'ListOfEmailAddressesWindow.show

ListOfEmailAddressesWindow.Refresh

The problem is that when there is only one email the number of unique emails is 0, but I am expecting 1, what am I doing wrong?

Thanks.

Lennox

The reported fault could not be reproduced.

Following code seems to show correct results on Xojo v2014r2.1 on Windows 7.

[code] //Remove the duplicate email addresses only
Dim z as integer
Dim TheEmailAddressOnlyString As String
Dim TheEmailAddressOnly As String

//
// All of the following combinations show correct results
//
// Remove comment mark as required from one of the assigment statements below.
//

// One unique address
'TheEmailAddressOnlyString = “MyAddress@MyEmail.com

// Two
'TheEmailAddressOnlyString = “MyAddress1@MyEmail1.com” + Chr(13) + “MyAddress2@MyEmail2.com” + Chr(13) + “MyAddress2@MyEmail2.com

// Three
'TheEmailAddressOnlyString = “MyAddress1@MyEmail1.com” + Chr(13) + “MyAddress2@MyEmail2.com” + Chr(13) + “MyAddress3@MyEmail3.com

// One
'TheEmailAddressOnlyString = “MyAddress1@MyEmail1.com” + Chr(13) + “MyAddress1@MyEmail1.com” + Chr(13) + “MyAddress1@MyEmail1.com

TheEmailAddressOnlyString = Trim(TheEmailAddressOnlyString)

Dim myArray() As String
myArray() = Split(TheEmailAddressOnlyString, Chr(13))
'msgbox Str(ubound(myArray()))

dim first_array() As string = myArray()
dim second_array(-1) As string

for i as integer = 0 to ubound(first_array())
if second_array().indexof(first_array(i)) < 0 then
second_array().append(first_array(i))
Z = Z + 1
end if
next

TheEmailAddressOnly = join(second_array, Chr(13))
TheEmailAddressOnly = Trim(TheEmailAddressOnly)

Window1.TextArea3.Text = “”
Window1.TextArea3.Text = TheEmailAddressOnly

If Z = 1 then
Window1.StaticText2.Text = “There is only one unique email address”
else
Window1.StaticText3.Text = “There are " + Str(Z) + " unique email addresses”
end if

'ListOfEmailAddressesWindow.show

Window1.Refresh[/code]

Thanks Syed,

The problem is with my code…
TheEmailAddressOnlyString is an empty string.

Thanks again.

Lennox

This whole process seems inefficient. Do you need the email addressed in their presented order? If not why not sort the array then from top to bottom simply remove the duplicates? e.g.

[code]Dim myArray() As String
myArray() = Split(TheEmailAddressOnlyString, Chr(13))
myArray.Sort

For i As Integer = myArray.Ubound DownTo 1
If myArray(i) = myArray(i - 1) Then
myArray.Remove i
End If
Next

TheEmailAddressOnly = joinmyArray, Chr(13))
Window1.TextArea3.Text = TheEmailAddressOnly

If myArray.Ubound = 0 Then
  Window1.StaticText2.Text = "There is only one unique email address"

else
Window1.StaticText3.Text = “There are " + Str(myArray.Ubound + 1) + " unique email addresses”
end if

[/code]

and if you DO need them in the original order. create an Integer Array to hold the current index location,
use SORTWITH , follow the above code, removing from both arrays at the same time…

when done… reverse the SortWith and your array is back in original order, with all duplicates removed.

of course if #7 and #13 are duplicates, you can’t be sure which will be kept

Thanks Lennox.

Hi Lenox

The dictionary class makes magic

[code] dim myArrayEmail(8) As String

//setting myArrayEmail
myArrayEmail(0) = “mail1”
myArrayEmail(1) = “mail2”
myArrayEmail(2) = “mail1”
myArrayEmail(3) = “mail3”
myArrayEmail(4) = “mail0”
myArrayEmail(5) = “mail4”
myArrayEmail(6) = “mail4”
myArrayEmail(7) = “mail5”

//The dictionary class does not accept duplicate key , so that I 'm worth
dim d as new Dictionary
dim longArray As Integer = myArrayEmail.Ubound-1

for position as Integer = 0 to longArray
d.Value(myArrayEmail(position)) = position
Next
//Break

//Done, now we have to get the solution of the dictionary
dim longDictionary As Integer = d.Count-1
ReDim myArrayEmail(longDictionary)

for position as Integer = 0 to longDictionary
myArrayEmail(position) = d.Key(position)
next
Break[/code]

Hello,

[quote=145472:@Syed Hassan]dim first_array() As string = myArray()
dim second_array(-1) As string

for i as integer = 0 to ubound(first_array())
if second_array().indexof(first_array(i)) < 0 then
second_array().append(first_array(i))
Z = Z + 1
end if
next[/quote]

Could someone explain, pseudocode, this line of code for me please…
if second_array().indexof(first_array(i)) < 0 then

Thanks.

Lennox

[quote=421498:@Lennox Jacob]Could someone explain, pseudocode, this line of code for me please…
if second_array().indexof(first_array(i)) < 0 then[/quote]
It’s a condensed check to see if the second array has an element from the first array.
IndexOf will get the index of an element being looked for, and if it’s less than zero (-1) the element does not exist in the array.
http://documentation.xojo.com/api/language/indexof.html

[code] for position as Integer = 0 to longDictionary
myArrayEmail(position) = d.Key(position)
next

[code]

That might give you an array with missing elements

Thanks Tim,

I thought as much, could you simplify it a little for me, break it up into parts? I don’t understand this part “< 0 then”

dim second_array(-1) As string // This is creating memory for a the second array which does not have any elements as yet

for i as integer = 0 to ubound(first_array()) // Taking one element of the first array at a time, check to see if that element is already in the second array

if second_array().indexof(first_array(i)) < 0 then // if it doesn’t, then append it
// I know that is what it is saying, but I don’t understand, maybe there are a few steps combined into one

second_array().append(first_array(i))
Z = Z + 1
end if
next

Thanks.

Lennox

This code assumes that you have an existing string array called arsWorkingValues. This code will read through them, and add the items to an array called arsUniqueValues that will only have one of every item - no duplicates. The top block is easier to read with code highlighting.

// This creates the memory for the unique values. It does not have any values yet.
// Passing -1 as the size is optional, and I prefer not to - this jumps out to me as
// an array declaration because of my standard code formatting.
dim arsUniqueValues() as String

// Take one element at a time from the working values
for i as Integer = 0 to arsWorkingValues.Ubound
  // Get the string from the array to work with, this makes the loop easier to read
  // if you have a longer for...next loop. I normally name it sThis, borrowed from Javascript.
  dim sThisValue as String = arsWorkingValues(i)  
  
  // Find the index of this value in the unique values array
  dim iValueIndex as Integer = arsUniqueValues.IndexOf(sThisValue)

  // If the current value we are working with is not found in the arsUniqueValues
  // array, the index returned from the IndexOf function will be -1
  if iValueIndex < 0 then
    // Here, we know that the sThisValue is not yet in arsUniqueValues
    // So we will add it
    arsUniqueValues.Append(sThisValue)

    // Now that the value is in arsUniqueValues, the next iteration of the for...next loop
    // will report an index greater than -1, and this if block will be skipped

  end

next

// At the end of this code, arsUniqueValues now has only one of each value from the
// arsWorkingValues array even if there are multiple of the same value.

I hope that helps. I broke the function out into more variables to help comment and follow along. Everyone’s brains work differently, so below is an alternate version of the function that works similarly, but inverts the check for the existing index.

dim arsUniqueValues() as String

for i as Integer = 0 to arsWorkingValues.Ubound
  dim sThis as String = arsWorkingValues(i)  

  dim iValueIndex as Integer = arsUniqueValues.IndexOf(sThis)

  // If sThis was found in the arsUniqueValues array, skip the rest of this loop.
  if iValueIndex > -1 then continue

  // If the code execution gets here, we know the element doesn't exist
  // in the unique values yet - so we'll add it now.
  arsUniqueValues.Append(sThis)

next

// Just like the version above, arsUniqueValues will only have one of every
// element from arsWorkingValues at this point
dim s as string = first_array(i)
dim n as integer = second_array.indexof(s)
if n < 0 then   // indexof returns -1 if s is not found in second_array

Thanks Tim and Tim,

Got it now.

Thanks again.

Lennox