Home > Enterprise >  IndexOf and Predicate
IndexOf and Predicate

Time:10-17


  public static int IndexOf(Product[] products, Predicate<Product> predicate)
      {
          if (products == null)
          {
              throw new ArgumentNullException();
          }
  
          for (int i = 0; i <= products.Length - 1;  i  )
          {
              if (predicate == null)
              {
                  throw new ArgumentNullException();
              }
              Product product = products[i];
              if (predicate(product))
              {
                  return i;
              }
          }
          return -1;
      }

  1. Searches for the index of a product in an products based on a predicate products Products used for searching predicate Product predicate If match found then returns index of product in products otherwise -1 I am asked to make changes only in the IndexOf(Product[] products, Predict predict) method without touching the Product model.

   [Test]
           public void IndexOf_Products_ReturnsTwo()
           {
               var products = new Product[]
               {
                   new Product("Product 1", 10.0d),
                   new Product("Product 2", 20.0d),
                   new Product("Product 3", 30.0d),
               };
               var productToFind = new Product("Product 3", 30.0d);
   
               int index = Utilities.IndexOf(products, product => product.Equals(productToFind));
   
               Assert.That(index, Is.EqualTo(2));
           }

  1. Expected: 2 But was:-1

    public class Product
   {
       public Product(string name, double price)
       {
           Name = name;
           Price = price;
       }
   
       public string Name { get; set; }
   
       public double Price { get; set; }
   
   }

CodePudding user response:

Well IndexOf is a correct implementation, which can be make to more general:

  public static int IndexOf<T>(IEnumerable<T> source, Predicate<T> predicate)
  {
      if (source is null)
      {
          throw new ArgumentNullException(nameof(source));
      }

      if (predicate == null)
      {
          throw new ArgumentNullException(nameof(predicate));
      }
    
      int index = 0;
      
      foreach (T item in source) {
          if (predicate(item))
              return index;

          index  = 1;   
      } 

      return -1;
  }

The actual problem seems to be with Product class which doesn't override Equals and GetHashCode methods. Without Equals and GetHashCode .net compare references (which are different), not values.

To compare by values you should explain .net how to do it, something like this:

// Let Product be equatable with Product - IEquatable<Product>
public class Product : IEquatable<Product> {
  ...

  // Let .net know how to compare for equality:
  //TODO: put the right names for Name and Price
  public bool Equals(Product other) => other != null &&
    other.Name == Name &&
    other.Price == Price;

  public override bool Equals(object o) => o is Product other && Equals(other);

  public override int GetHashCode() => HashCode.Combine(Name, Price);
}

Edit: if you can't change Product class, you have to change predicate and explain there how to compare for equality:

int index = Utilities
  .IndexOf(products, product => productToFind.Name == product.Name &&
                                productToFind.Price == product.Price);
   

Please, fiddle youself.

  • Related