-4

If I declare a List like,

List<object[]> People = new List<object[]>();

(in which object[] has two elements)

People.Add(new object[] {"Sam", 18});

Is there a way I can find the index of a person like this?

People.IndexOf(new object[] {"Sam", 18});

I've tried doing it like it is above, but it returns -1.


Solved this in my own crappy way by creating an extension method which takes a string parameter and loops through the list until it matches with one, then returns that index.

public static int OIndexOf(this List<object[]> List, string Check)
{
    for (int I = 0; I < List.Count; I++)
    {
        if ((string)List[I][0] == Check)
            return I;
    }
    return -1;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tsji
  • 5
  • 3
  • 3
    Think about what the word `new` means. – Jonathon Reinhart Apr 18 '21 at 22:18
  • I think you could definitely be using the object from object-oriented to help you solve this problem here. Why are you using an array of objects to describe an entity for which you have a structured pattern? Make a class with each field and override equals. – Omar Abdel Bari Apr 18 '21 at 23:52
  • Thanks for pointing out my oversight, although my original point is asking for a similar alternative. – Tsji Apr 19 '21 at 01:04

4 Answers4

1

Generally speaking, you're going to need a concrete type to make this work, like a Person object or an int value.

The reason this is the case is because your type must implement an .Equals() method. It won't work with object objects, because the .Equals method for object compares references, not values, and your comparison will always return false unless you have the original object (not the case in your code, where you're creating a new object for comparison.

From the documentation for the IndexOf method:

This method searches all the elements of a one-dimensional array for value. To determine whether value exists in array, the method performs an equality comparison by calling each element's Equals method until it finds a match. This means that if the element overrides the Object.Equals(Object) method, that override is called.

Therefore, you need a Person object with an Equals() override. To wit:

public class Person
{
    public string Name { get; set; }

    public override bool Equals(Person other)
    {
        return Name.Equals(other.Name);
    }
}

If you want to compare an array of people, you need another type that encapsulates your Person array, and an Equals() method to check equality of every person in the array with every person in the other array.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • It seems to me that this answer completely misses the point of the question. First, a `List` would work fine _as long as the actual runtime type of the object overrides `Equals()`_. No concrete, non-`object` type is needed. Second, the OP's example is a `List`, which means the real problem here is that arrays don't implement value-equality, so one would have to implement a custom `IndexOf()` (e.g. extension) method that knows how to compare arrays for value-equality. – Peter Duniho Apr 18 '21 at 22:34
  • Read the last sentence of my answer. – Robert Harvey Apr 18 '21 at 22:35
  • Yeah, so? The first part of your answer is just plain wrong. Or at the very least, you've failed to express yourself precisely enough to convey the information that actually needs to be conveyed. (Yes, array's don't override `Equals()`, but your post doesn't seem to be discussing that, or discussing overrides at all) – Peter Duniho Apr 18 '21 at 22:36
  • You said it yourself; you can use object, but the runtime type needs to be something that implements `Equals()` which means you still need a concrete type, unless you can think of a way to implement Equals() in a class without actually creating the class. – Robert Harvey Apr 18 '21 at 22:37
  • https://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden – Antonín Lejsek Apr 18 '21 at 23:18
  • Thank you for the explanation. I'll try putting in what you've explained to me. I'll get back to you as soon as I can. – Tsji Apr 19 '21 at 01:10
0

If you had a reference to the actual array you wanted to look for then IndexOf would work in the way you want. But you are creating a new array, so it won't work.

The simplest way to do what you want is to use FindIndex:

People.FindIndex(p => p[0] == "Sam" && p[1] == 18)

To compare to the whole of an array in a variable at the same indices, use LINQ's SequenceEqual

var arr = new object[] {"Sam", 18};
People.FindIndex(p => arr.SequenceEqual(p));
Charlieface
  • 52,284
  • 6
  • 19
  • 43
0

If you really want to do it, you have to do it yourself.

Example: Create a new function:

int NewIndexOf(people, item)
{
    int index = 0;
    if(people.length) < 2
        return -1;

    foreach(var p in people)
    {
        p[0].Equals("Sam") && p[1].Equals(18)
        return index;
        ++index;
    }
    return -1;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Well, IndexOf uses the default equality comparer for a given type - Object, which is in your case comparers references. You have two new - two different referencies, which in turn means that both instances are considered unequal. To solve the problem you can:

Implement your own class:

 public class Person : IEquatable<Person> {
   public Person(string name, int age) {
     if (null == name)
       throw new ArgumentNullException(nameof(name));
     if (age < 0)
       throw new ArgumentOutOfRangeException(nameof(age));

     Name = name;
     Age = age;
   }

   public String Name {get;}

   public int Age {get;}

   public bool Equals(Person other) =>
     other != null && other.Name == Name && other.Age == Age;

   public override bool Equals(Object o) => Equals(o as Person);

   public override int GetHashCode() => Name.GetHashCode() ^ Age;
 }

Then you can put

 List<Person> People = new List<Person>();

 People.Add(new Person("Sam", 18));

 // Now .NET knows how to compare Person instances
 int index = People.IndexOf(new Person("Sam", 18));

Another approach (not a good practice, though) is to find index manually, with a help of LINQ:

 List<object[]> People = new List<object[]>();

 ...

 var index = People
    .Select((v, i) => new { v, i })
    .FirstOrDefault(pair => pair.v.SequenceEqual(new object[] { "Sam", 18 }))
   ?.i ?? -1;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215