user48743
user48743

Reputation: 15

List<T> BinarySearch using a String indexer

So I have a CreditCard class that has some properties, one of which is for the card number as a String (public string Number { get; set; }). I'm storing the CreditCard objects in a CreditCardList class which has the variable List (private List<CreditCard> cclist = new List<CreditCard>();). I want to be able to retrieve a CreditCard by its card number by sorting the List first, then using the BinarySearch method on the List. I also want to do this by passing a String indexer of the number to search for into the BinarySearch method, along with a comparer if I need one.

This is what I have so far for the method to get the CreditCard matching the number, but Visual Studio 2013 gives me an error on the line: int index = cclist.BinarySearch(cclist[input], new CreditCardComparer()); "the best overloaded method match for 'System.Collections.Generic.List.this[int]' has some invalid arguments." I assume it's because I'm using the String indexer wrong or something.

public List<CreditCard> GetCardByNumber (string input)
{
    List<CreditCard> tempList = new List<CreditCard>();

    // save the current unsorted list to a temporary list to revert back to after sorting
    List<CreditCard> originalList = new List<CreditCard>(cclist.Capacity);

    for (int i = 0; i < cclist.Capacity; i++)
    {
        originalList[i] = cclist[i];
    }

    // begin sorting for binary search of card number
    cclist.Sort();

    int index = cclist.BinarySearch(cclist[input], new CreditCardComparer());

    if (index < 0)
    {
        tempList.Add(cclist[input]);
    }

    // revert back to the original unsorted list
    for (int i = 0; i < originalList.Capacity; i++)
    {
        cclist[i] = originalList[i];
    }

    // return the found credit card matching the specified number
    return tempList;
}// end GetCardByNumber (string input)

Here are my int and string indexers:

public CreditCard this[int i]
{
    get
    {
        if (i < 0 || i >= cclist.Count)
        {
            throw new ArgumentOutOfRangeException("index " + i + " does not exist");
        }

        return cclist[i];
    }
    set
    {
        if (i < 0 || i >= cclist.Count)
        {
            throw new ArgumentOutOfRangeException("index " + i + " does not exist");
        }

        cclist[i] = value;
        saveNeeded = true;
    }
}// end CreditCard this[int i]

public CreditCard this[string input]
{
    get
    {
        foreach (CreditCard cc in cclist)
        {
            if (cc.Number == input)
            {
                return cc;
            }
        }

        return null;
    }
}// end CreditCard this[string number]

And here is my comparer class:

public class CreditCardComparer : IComparer<CreditCard>
{
    public override int Compare(CreditCard x, CreditCard y)
    {
        return x.Number.CompareTo(y.Number);
    }
}// end CreditCardComparer : IComparer<CreditCard>

And lastly, here are the necessities for my list sorting and what not...

class CreditCard : IEquatable<CreditCard>, IComparable<CreditCard>
{
    public bool Equals (CreditCard other)
    {
        if (this.Number == other.Number)
        {
            return true;
        }
        else
        {
            return false;
        }
    }// end Equals(CreditCard other)

    public int CompareTo(CreditCard other)
    {
        return Number.CompareTo(other.Number);
    }// end CompareTo(CreditCard other)
}

Is it truly possible to do what I'm attempting, i.e. sending a string indexer that returns a CreditCard object based on a string into a BinarySearch method of List?

Also, I can provide any more code if necessary, but I felt like this was a little much to begin with.

Upvotes: 0

Views: 465

Answers (2)

Ichabod Clay
Ichabod Clay

Reputation: 2011

There are a couple things amiss in your GetCardByNumber method. First is the method returns an entire list instead of a single CreditCard, which goes against the method name. Second, the binary search is not even needed since you do the searching in the string indexer first:

public CreditCard this[string input]
{
    get
    {
        foreach (CreditCard cc in cclist)
        {
            if (cc.Number == input)
            {
                return cc;
            }
        }

        return null;
    }
}

By this point, you've already found the CreditCard with the information you need, so why search for it again in a BinarySearch? Thirdly, as was covered in landoncz's answer, you can't use a string as an index for a List<T>. What you probably intended to use was the CreditCardList instead of the List<CreditCard>

CreditCardList creditCardList = new CreditCardList();
creditCardList["1234"]; //correct

List<CreditCard> cclist = new List<CreditCard>();
cclist["1234"]; //incorrect. This is where your error is coming from.

If you're trying to access the indexer property inside of the class that implements it (which I'm assuming you are trying to do in your GetCardByNumber method), just use this[index]:

public class CreditCardList
{
    public CreditCard this[string s] { /*Implementation*/ }

    public CreditCard GetCard(string s)
    {
        return this[s]; // right here!
    }
}

Now... according to your comment, "Retrieve the CreditCard with a specified number if it exists using the BinarySearch method in List<T> in the implementation of a String indexer.", it seems to me that the assignment wants you doing something along these lines. (a thing to note is that I'm not sure of your entire implementation of the CreditCard class, so please excuse the naive instantiation in the following code)

public class CreditCardList
{
    private List<CreditCard> cclist = new List<CreditCard>();

    public CreditCardList()
    {
        //For the sake of an example, let's magically populate the list.
        MagicallyPopulateAList(cclist);
    }

    public CreditCard this[string s] /* In the implementation of a String indexer... */
    {
        get
        {
            CreditCard ccToSearchFor = new CreditCard() { Number = value };
            cclist.Sort();

            /* ...use the BinarySearch method... */
            int index = cclist.BinarySearch(ccToSearchFor);

            if (index >= 0)
                return cclist[index]; /* ...to retrieve a CreditCard. */
            else
                throw new ArgumentException("Credit Card Number not found.");
        }
    }
}

Upvotes: 0

landoncz
landoncz

Reputation: 2017

A System.Collections.Generic.List uses an int as the indexer property, it does not let you use a string.

If you want to use a string as your indexer (primary key), you should probably use a Dictionary<string,CreditCard> instead.

Upvotes: 1

Related Questions