7

Problem

Check collection contains the same number multiple times.

If it does contain the same numbers more than once, then I want to keep the first number and give a new value to the rest of the numbers, which are the same as the first one.

list newFitnessList does contain These numbers:

0. 4054.230995  --> after code= 4054.230995
1. 4041.416004  --> after code= 4041.416004
2. 3926.227397  --> after code= 3926.227397
3. 4722.250903  --> after code= 4722.250903
4. 4722.250903  --> after code= 0
5. 4226.636776  --> after code= 4226.636776
6. 4061.499026  --> after code= 4061.499026
7. 3876.278254  --> after code= 3876.278254
8. 4041.416004  --> after code= 0
9. 4779.468077  --> after code= 4779.468077
10. 4226.636776  --> after code= 0
11. 3876.278254  --> after code= 0
12. 4779.468077  --> after code= 0
13. 3926.227397  --> after code= 0

To achieve the solution explained above I tried the following code, but nothing is happening. The Output of the list is the same as before:

public List<double> sortDoppelganger(List<double> inputFitnessList)
{
  List<double> newFitnessList = inputFitnessList.ToList();
  for(int i = 0; i < newFitnessList.Count; i++)
  {
    double Nothing=0;
    double actual = newFitnessList[i];
    for(int j = newFitnessList.Count-1; j >= 0; j--)
    {
      double next = newFitnessList[j];
      if(actual == next)
      {
        next = Nothing;
      }
    }
  }
  return newFitnessList;
}

I would really appreciate it if someone has any idea what's wrong with my code. And maybe it would be better not to hide, that I'm a newbie with programming.

After reading the explanations: I tried out two idea's explained. First one was the idea of @Tim Schmelter and the second idea was from @user3185569.

And here you can take a look at what i was tyring to achieve: enter image description here

Here the suggestion of Tim: enter image description here

Here the Suggestion of user3185569: enter image description here

Meliss
  • 153
  • 1
  • 9
  • 1
    use Double.Equals to compare Double : https://msdn.microsoft.com/en-us/library/ya2zha7s(v=vs.110).aspx –  Jul 18 '16 at 11:19
  • 1
    Your prediction for what the code does disagrees with what it actually does. To figure out why, use the debugger. With a debugger open and watchpoints set on `newFitenessList`, `actual`, and `next`, step through your code line by line. – Brian Jul 18 '16 at 11:19
  • replace next = Nothing; with newFitnessList[j] = Nothing – Peter Bons Jul 18 '16 at 11:20
  • @PeterBons: That's necessary but not sufficient to fix this code. – Brian Jul 18 '16 at 11:22

5 Answers5

8

You could use a HashSet<double> to find out if there's a duplicate:

public List<double> SortDoppelganger(List<double> inputFitnessList, double replacementValue = 0)
{
    HashSet<double> doppelgangerFinder = new HashSet<double>();
    for (int i = 0; i < inputFitnessList.Count; i++)
    {
        double value = inputFitnessList[i];
        bool istDoppelganger = !doppelgangerFinder.Add(value);
        if (istDoppelganger)
            inputFitnessList[i] = replacementValue;
    }
    return inputFitnessList;
}

This solution modifies the original list. If that's not desired create a copy at the beginning by using var newList = new List<double>(inputFitnessList).

For what it's worth, here is a generic extension method that works with any type:

public static List<T> ReplaceDuplicates<T>(this IEnumerable<T> sequence, T replacementValue)
{
    HashSet<T> duplicateFinder = new HashSet<T>();
    List<T> returnList = new List<T>();
    foreach (T item in sequence)
    {
        bool isDuplicate = !duplicateFinder.Add(item);
        returnList.Add(isDuplicate ? replacementValue : item);
    }
    return returnList;
}

Explanation: user3185569 is right, i have forgotten to mention what you've done wrong. The main problem is that you try to assign the replacement value to the local variable next:

double next = newFitnessList[j];
if(actual == next)
{
  next = Nothing;
}

It has nothing to do with value- or reference-types differences in this case. The only reason why this doesn't work is that you modify only the value of the variable. Not the value the variable was referencing before(newFitnessList[j]). The variable does not even know that it was linked to the list. It just knows the value to store. If it was a reference type the problem would be the same. By replacing it with another value the list won't be modifed at all.

To cut a long story short, this would fix the main problem:

double next = newFitnessList[j];
if(actual == next)
{
  newFitnessList[j] = Nothing;
}
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • 2
    I think if the use is going to learn anything from his mistakes, he needs to know what is wrong with his code which is better than providing another approach for him. With this answer, the user doesn't know why using **copy local variable** doesn't affect the values inside his List. He doesn't either know the difference between a reference type and a Value-Type which might let him face the same mistake in the future. – Zein Makki Jul 18 '16 at 11:42
  • @user3185569: point taken and edited my answer accordingly. But how are value-/reference-types related at all? The problem would remain if it was a class instead of a double. – Tim Schmelter Jul 18 '16 at 12:00
  • If the types inside the list were reference types `next.SomeProperty = newVal;` would have changed the value inside the list. `next = new ...` or `next = null` or `next = someOtherNext` is a different story. – Zein Makki Jul 18 '16 at 12:03
  • @user3185569: that's something different. But if `next` was a reference type it wouldn't change anything. – Tim Schmelter Jul 18 '16 at 12:06
  • Thank you so much Tim, it worked like magic :) First my List was in type double and I guess because of that my List still contained a few numbers, which are the same. To controll whether the cause was the type of double, I converted my List to integers... and it worked, there are no numbers anymore which are the same. How do you know all of that? I was searching and trying like crazy, but nothing worked until I saw your solution. Thank you! – Meliss Jul 18 '16 at 12:40
2

Problems with your code:

1- next is a local value-Type variable, so you're actually changing nothing inside the list.

2- You need to skip the case where i == j or you'll get all your values as 0 (Item matching itself)

public static List<double> sortDoppelganger(List<double> inputFitnessList)
{
    List<double> newFitnessList = inputFitnessList.ToList();
    for (int i = 0; i < newFitnessList.Count; i++)
    {
        double Nothing = 0;
        double actual = newFitnessList[i];
        for (int j = newFitnessList.Count - 1; j >= 0; j--)
        {
            if (j == i)
                continue;

            double next = newFitnessList[j];
            if (actual == next)
            {
                newFitnessList[j] = Nothing;
            }
        }
    }
    return newFitnessList;
}

You may need to replace if (actual == next) with (Math.Abs(actual - next) < 0.0001) as you can't trust double with exact comparisons.

Usage:

var newList = sortDoppelganger(list);

Things to learn from your mistake:

When you write double next = newFitnessList[j]; you're actually copying the value at that index of the list to a local variable named next. Since the type is double (A Value-Type), changing next doesn't change anything inside your List.

However, if you're using a reference type (A Customer Class instead of double for example), changing the value of the properties of next would change them inside the list.

Zein Makki
  • 29,485
  • 6
  • 52
  • 63
  • He doesn't change the value of the `actual` variable, he just uses it to compare it with all following. – Tim Schmelter Jul 18 '16 at 11:52
  • @TimSchmelter i meant `next` – Zein Makki Jul 18 '16 at 11:53
  • you're right, i should have explained it more instead of only providing another solution. But the problem has nothing to do with value-/reference-types but only with the fact that you don't modify the original storage of a value if you replace a local variable since a variable is not linked to the original source of it's value. – Tim Schmelter Jul 18 '16 at 12:04
  • What is Happening with << if(j==i) continue; >> ? If I leave it out all values change to zero and if I don't leave it out, only the ones change to zero, which I want to. Maybe it checks whether I compare the number for example at index [3] with the number at [3]. And if it is like that, then it continues to the number at next index? – Meliss Jul 18 '16 at 13:33
  • @Meliss If `i == j`, then you're comparing the item on the same index, which is surely the same item. You don't want that. You need to compare each item to the other items only. `continue` skips the current iteration and moves to the next one. – Zein Makki Jul 18 '16 at 13:35
  • Ok thank you very much. Everything is working appropriately now. – Meliss Jul 18 '16 at 13:39
0

Nothing is 0, so it is setting the List values to 0.

You can use this to check for duplicates:

bool areDduplicates = lstNames.GroupBy(n => n).Any(c => c.Count() > 1);

From here.

Community
  • 1
  • 1
0
private static IEnumerable<double> sortDoppelganger(List<double> doubles)
{
  var newList = new List<double>();
  foreach (var t in doubles)
  {
    newList.Add(newList.Contains(t) ? 0.0 : t);
  }
  return newList;
}
0
public List<double> filterlist(List<double> lst)
        {
            List<double> lstDouble = new List<double>();

            for (int i = 0; i < lst.Count; i++)
            {
                if (lstDouble.Contains(lst[i]))
                {
                    lstDouble.Add(0);
                }
                else
                {
                    lstDouble.Add(lst[i]);
                }
            }
            return lstDouble;
        }