Matching duplicate values in an array

I was wondering if there’s a way to determine which values are duplicated in an array?

There are many. All are brute force. It depends on the desired result. Do you want a list of dupes? A list of non dupes? Or an array that contains all but one of the dup values removed, so there are no more dupes?

Hi Tim! So I’m not looking to remove the duplicate values but rather get the app to list the values that are duplicated and how many duplications there are for each value.

So what I have is a listbox that contains a number in each row. I created an array that contains this list of numbers. Now I want to know which numbers are repeating and how many times.

I’d use a dictionary. Check if the value exists already in the dictionary. If not, add your value as the Key and 1 for the dictionary Value. If it does, add 1 to the dictionary value. Then loop through the dictionary and pull all the keys that have a value greater than 1. The dictionary value is the number of times the key repeated.

5 Likes

You could use Dictionary.lookup to do this more cleanly as well:

Dict.value(a) = Dict.Lookup(a,0) + 1

5 Likes

Thanks Tim & Greg. I will definitely give this a try.

Hello,
103 / 5.000

Übersetzungsergebnisse

Hello Markus
if only one display is desired, the values can be counted by sorting see example

https://www.dropbox.com/s/g6m73glxnljwybg/%20Listbox-dublicated%20entries-API2.xojo_binary_project?dl=1

1 Like

A quick & dirty example of the approach @Tim_Hare suggested:

Var NumbersList As New Dictionary
Var RandomNumber As Integer

For X As Integer = 0 To 100
  
  RandomNumber = System.Random.LessThan(25)
  
  If Not NumbersList.HasKey(RandomNumber) Then
    
    NumbersList.Value(RandomNumber) = 1
    
  Else
    
    NumbersList.Value(RandomNumber) = NumbersList.Value(RandomNumber)+1
    
  End If
  
Next

Var DoublesMessage As String

For Each key As Variant In NumbersList.Keys
  
  If NumbersList.Value(key) > 1 Then
    
    DoublesMessage = DoublesMessage + "The Number " + key.StringValue + " is contained " + Str(NumbersList.Value(key)) + " times." + EndOfLine
    
  End If
  
Next

MessageBox DoublesMessage
1 Like

And @Greg_O suggestion in comparison:

Var NumbersList As New Dictionary
Var RandomNumber As Integer

For X As Integer = 0 To 100
  
  RandomNumber = System.Random.LessThan(25)
  
  NumbersList.Value(RandomNumber) = NumbersList.Lookup(RandomNumber,0)+1
  
Next

Var DoublesMessage As String

For Each key As Variant In NumbersList.Keys
  
  If NumbersList.Value(key) > 1 Then
    
    DoublesMessage = DoublesMessage + "The Number " + key.StringValue + " is contained " + Str(NumbersList.Value(key)) + " times." + EndOfLine
    
  End If
  
Next

MessageBox DoublesMessage

Sorry, but i had a few moments of spare time and needed something to do :wink:

1 Like

Thanks Sascha! So the example you gave worked perfectly for the random number. However, when I tried to implement the array I created from the listbox, I’m getting no results.

var numberslist as new dictionary

for i as integer = 0 to list.listcount - 1

  var str() as string = array(list.cell(i,0))
  numberslist.value(i) = numberslist.lookup(str,0)+1

next i


Var DoublesMessage As String

for each key as variant in numberslist.keys
  
  if numberslist.value(key) > 1 Then
    
    DoublesMessage = DoublesMessage + "The Number " + key.StringValue + " is contained " + Str(NumbersList.Value(key)) + " times." + EndOfLine
    
  End If
  
Next

msgbox doublesmessage

What could I be doing wrong?

I’m also slightly confused on where the count is taking place or how it’s taking place. I’m assuming here

NumbersList.Value(RandomNumber) = NumbersList.Lookup(RandomNumber,0)+1

Another possibility is to use an in memory database /recordset

If you populate that with all your records…

1
1
1
3
3
2
4
1
5

Then you can get your list using a simple SQL query

Select number, count(1) as tot group by tot having tot >1 ;

From the list above, you would get rows containing
1 , 4 and
3, 2

1 Like

This doesn’t look anything like what @Greg_O posted.

Well I thought that I should modify the values since I’m not looking for a list of random numbers. Unless I’m misunderstanding this line of code…and apparently I am. Which is why I’m here.

If you see the code posted by Sasha:

RandomNumber = System.Random.LessThan(25)
NumbersList.Value(RandomNumber) = NumbersList.Lookup(RandomNumber,0)+1

then your code:

  var str() as string = array(list.cell(i,0))
  numberslist.value(i) = numberslist.lookup(str,0)+1

I guess what you want is something like:

var mynumber as integer = Listbox1.Cell(i,0).ToInteger //or CellTextAt
numberslist.value(mynumber) = numberslist.lookup(mynumber,0)+1
2 Likes

You’re using the row number as the dictionary key. That will always be unique. You should use the value of the listbox as the dictionary key. (And it can be a string, you don’t have to convert it to an integer.)

1 Like

The line of code is intended to increment the value assigned for a particular key in the dictionary, whether or not (and this is the important part of the deal) that key already exists (more exactly, to initialise the value if it does not). If you were to lookup the doc for .Value and .Lookup, you’d see that you can’t have .Value on the RHS because if the key doesn’t exist, then you get an exception. IOW, you can’t do something likre:

Dict.Value(a) = Dict.Value(a) + 1

unless you know that this key is already in the dictionary and its .Value is zero.

@Greg_O 's neat trick relies on the fact that .Lookup doesn’t mind if the key exists or not. If it does not, then .Lookup just returns the second argument, zero in this case. Thus for a non-existent key the result is to create the key and set the value to one, the desired outcome.

3 Likes

@Tim_Hare yep that was the issue. I didn’t think about the fact that the value couldn’t be unique.

@TimStreater thanks for explaining. I’ve been using xojo since it was Realbasic 5.5 version and I’m just now starting to actually understand certain functions. It’s like things are much more easier to comprehend. So I will definitely start to research dictionary more. I really appreciate everyone for helping out.

1 Like

not sure how fast (or slow) the dictionary approach is, but what I do is sort the array then run down it looking for identical adjacent values ie if x(j) = x(j+1), if so, you have a duplicate, then index down to the next different value and keep looking for another match @ j & j+1.