Daniel G Daniel G - 3 months ago 22
C# Question

C# XNA/MonoGame Paging: How To Prevent Duplicates

So, lately I've been having a problem. Some of you may have seen my post on Writing Lists to and from Binary Files. This time, though, it's not the Users. It's the Interfaces.

I've created a game where you can create a user, and the User is displayed using the UserInterface class, which allows you to click on the username to sign in or click on the trash can to delete the user. However, I realized that if you create more than 4 users, they start to go off-screen. So, I began implementing paging.

That's where I have the problem.

I created 5 users: z, x, c, v, and b. The first page has z, x, c, and v drawn correctly. However, on page 2, b is drawn twice. And when I created another user, "n", they were drawn on the 2nd and 3rd page.

I've been trying a few different solutions. One was to try and find and delete each duplicate. However, I feel like this isn't very efficient, so I abandoned it.

I have looked up how to prevent duplicates in lists, but there's my problem: I have a List>, which is a List to keep track of each page, which keeps track of each of it's UserInterfaces.

Here's some of my code:

List<UserInterface> interfaces; // This is all the interfaces
int page = 0;
List<List<UserInterface>> pages; // This is the list of pages of interfaces
const int INTERFACES_PER_PAGE = 4;

public Menu(args...)
{
if (User.LoadUsers() /*User.LoadUsers returns a list with all the saved users*/ != null)
{
foreach (User u in User.LoadUsers())
{
UserInterface interfaceToAdd = new UserInterface(u, content, trashAsset, bigFont, whiteRectangleAsset, 0, 0,
whenUsernameClicked, whenTrashClicked);
interfaces.Add(interfaceToAdd);
UpdatePagesToInterfaces();
}
}
}


And here's the Update method:

public void Update(args...)
{
for (int i = 0; i < pages.Count; i++)
{
if (pages[i].Count == 0)
{
pages.RemoveAt(i);
}
}

while (page > pages.Count - 1)
{
page--;
}

if (interfaces.Count != interfaces.Distinct().Count())
{
interfaces = interfaces.Distinct().ToList();
UpdatePagesToInterfaces();
}
if (pages.Count > 0)
{
for (int i = 0; i < pages[page].Count; i++)
{
pages[page][i].Update();
}
}
// More updating, and code to update the next and previous page buttons
}


Here are the private methods.

private void UpdatePagesToInterfaces()
{
// This method is very inefficient
pages.Clear();
foreach (UserInterface ui in interfaces)
{
AddUser(ui);
}
}

private void AddUser(UserInterface userInterface)
{
// This method makes sure that the new interface is added to the correct
// page.
UserInterface interfaceToAdd = userInterface;

// This gets the currently used page and adds to it.

if (pages.Count > 0)
{
for (int i = 0; i < pages.Count; i++)
{
if (pages[i].Count < INTERFACES_PER_PAGE)
{
pages[i].Add(interfaceToAdd);
}
else
{
pages.Add(new List<UserInterface>());
pages[i + 1].Add(interfaceToAdd);
}
}
}
else // pages.Count <= 0
{
pages.Add(new List<UserInterface>());
pages[pages.Count - 1].Add(interfaceToAdd);
}
}


As you can see, the UpdatePagesToInterfaces method is very inefficient; what I'm trying to do here is find duplicates, then delete them. However, I'd like to just prevent duplicates altogether. Any ideas?

Note: I'm 13, so I may not understand some of the advanced terms adults may use. Please make sure the answer isn't too hard to understand.

Thanks in advance!

Answer
 for (int i = 0; i < pages.Count; i++)
        {
            if (pages[i].Count < INTERFACES_PER_PAGE)
            {
                pages[i].Add(interfaceToAdd);
            }
            else
            {
                pages.Add(new List<UserInterface>());
                pages[i + 1].Add(interfaceToAdd);
            }
        }

Lets say I=0 and the page I=0 is full and page I=1 has no elements in it, then we will add user to I=0+1=1 page. Ok, done. Now page I=0 is full and I=1 has one user. On the next step of the loop we'll look if the page (now I=1) has spare slots. And it has! So we will add the same user again.

How did it come to this?!

You see, ListT.Count is a property. So it will be re-calculated for check on each step of the loop. So after pages.Add(...) pages.Count will be 2, not 1 and we will fall into the next step.

That's what I see with my eyes.

Also no offence, but please, use debugger (and make your code examples shorter). I suppose you could easily find this yourself with the help of step-by-step execution.

Also your loop logic is flawed. When you find that the page I is full, you automatically add element to the next page. But it could be full also, and you need to check it.

Comments