0

I have a List<List<string>> and it appears like this:

[0]
    [0]Elephant 
    [1]26
    [2]Thailand
[1] 
    [0]Elephant 
    [1]40
    [2]Thailand
[2] 
    [0]Ant
    [1]2
    [2]Australia
[3] 
    [0]Camel Red hump
    [1]1
    [2]Nigeria

I want to find the index where the word Camel is found ex: 3.

int index= animals.FindIndex(r => r.Contains("Camel"));

However, the above code returns -1. How can I solve this ?

5
  • 4
    The outer list seems to contain structured data. Can't you create a class? Commented Mar 14, 2019 at 17:32
  • 8
    You've described some code and said that it fails. How should we know why? We can't see the failing code. Show us the code. Give us a short program that runs that we can look at; if you do that, either the bug will become obvious to you, or it will be obvious to us. But without the code, we can't tell what you're doing wrong. Commented Mar 14, 2019 at 17:33
  • I have come far with this method. Is there a workaround ? Commented Mar 14, 2019 at 17:33
  • foreach top level item, .FindIndex(). Commented Mar 14, 2019 at 17:35
  • You can use nested for loop to scan the entire list to find your index and break once you found it Commented Mar 14, 2019 at 17:41

3 Answers 3

8

Not reproducible:

using System;
using System.Collections.Generic;
public class Program
{
    public static void Main()
    {
        var animals = new List<List<string>>()
        {
            new List<string> { "Elephant", "26", "Thailand" },
            new List<string> { "Elephant", "40", "Thailand" },
            new List<string> { "Ant", "2", "Australia" },
            new List<string> { "Camel", "1", "Nigeria" }
        };
        int index= animals.FindIndex(r => r.Contains("Camel"));
        Console.WriteLine(index);
    }
}

That prints 3, as expected. You are doing something wrong in code you have not shown us. Show us the code that is failing. Take the code above that I just wrote, which is a complete program that you can cut-n-paste and execute, and modify it so that it demonstrates your bug. By doing so, you will either find the bug, or you will write a program where it is clear to others what the bug is.


UPDATE: The problem is not as stated. In the future, please write questions that describe the problem you actually have. That saves everyone involved from wasting time looking at the wrong problem.

The real problem is:

    var animals = new List<List<string>>()
    {
        new List<string> { "Elephant", "26", "Thailand" },
        new List<string> { "Elephant", "40", "Thailand" },
        new List<string> { "Ant", "2", "Australia" },
        new List<string> { "Camel red hump", "1", "Nigeria" }
    };

And we wish to find item 3 based on the query string "Camel".

Here's how you attack this problem. First, you solve it for a single string:

string test1 = "Foo Bar Blah";
string test2 = "Camel red hump";

What do we want? We want to know if "Camel" appears in a string. That is done with string.Contains:

Console.WriteLine(test1.Contains("Camel")); // False
Console.WriteLine(test2.Contains("Camel")); // True

All right. We can solve the problem for a single string. Now solve the problem for a list of strings:

var list1 = new List<string> { "Ant", "2", "Australia" };
var list2 = new List<string> { "Camel red hump", "1", "Nigeria" };

We wish to know if the predicate string.Contains("Camel") is true for any member of list1 or list2. So use Any:

(Remember to add using System.Linq; to use the Any sequence method.)

Console.WriteLine(list1.Any(s => s.Contains("Camel")); // False
Console.WriteLine(list2.Any(s => s.Contains("Camel")); // True

Great, we now have a predicate that applies to lists of strings. Now we wish to apply that to a list of lists of strings:

var index = animals.FindIndex(
  list => list.Any(
    s => s.Contains("Camel"))); 
// Prints 3

You see what I did there? The methodology you should use for attacking problems on sequences-of-sequences is to solve the problem on individual elements first, then extend that solution to sequence-of-elements, and then extend that solution to sequence-of-sequence-of-elements, and so on. Build up from simple problems to harder problems.

Now, all that said, Any is probably the wrong predicate to use. If you have an animal new List<string>{"Canada Goose", "123", "United States"} and an animal new List<string>{"Wolverine", "4567", "Canada"} you run the risk of searching for Canada and finding the wolverine when you are looking for the Canada goose. You should probably not be representing this data as List<List<string>> in the first place. You should be doing this:

class Animal
{
  public string Kind { get; }
  public int Size { get; }
  public string Country { get; }
  public Animal (string kind, int size, string country)
  {
    this.Kind = kind;
    ... and so on.

Now you can say:

 var animals = new List<Animal>()
    {
        new Animal("Elephant", 26, "Thailand"),
        new Animal("Elephant", 40, "Thailand"),
        new Animal("Ant", 2, "Australia"),
        new Animal("Camel red hump", 1, "Nigeria")
    };

And now your test is:

int index = animals.FindIndex(a => a.Kind.Contains("Camel"));

which is much easier to understand. Build types that represent concepts in your business domain. That will allow you to build programs that look like the concepts in your code, and not the mechanisms.

Sign up to request clarification or add additional context in comments.

2 Comments

I have updated my post. Instead of Camel the string is Camel red hump. I am using the code int index= animals.FindIndex(r => r.Contains("Camel")); but it returns -1. But when I search for the full string which is int index= animals.FindIndex(r => r.Contains("Camel red hump"));, it prints the correct index. Can you help me sort this out ?
@Illep: That's a totally different problem than the one you described, so it is no wonder that it has a different answer.
1

So you want to know if part of the string is present in some item of the List?

int index = animals.FindIndex(r=>r.Any(x=>x.Contains("Camel")));

Just to explain a little, your code was searching for an exact match, but you don't have the same string. So this answer search for the index of the first List (FindIndex) which at least one element (Any) contains (Contains) the string Camel. Note that the code is case sensitive.

Comments

1

@EricLippert answer is correct as usual, but let me try to refactor your code a bit more.

You have a list of lists of strings, and the sublist always contains:

  • On index 0, an animal
  • On index 1, an Id
  • On index 2, a country.

If this is the case for every entry on the list, then this is way better abstracted with a class:

public class MyItem
{
    public int Id { get; set; }
    public string Animal { get; set; }
    public string Country { get; set; }
}

Then, you can replace the List<List<string>> into something more useful and typed: List<MyItem>.

This way, you can use linq properly, for example:

var item = list.First(i => i.Animal.Contains("Camel"));

Using this strategy, you do not need to get the item index and after that get the other values.

1 Comment

Hah, I just made the same suggestion. Great minds think alike!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.