peter
peter

Reputation: 8682

Index was outside the bounds of the array in lambda expressions linq

How to check whether the array has minimum two counts in .net,I am getting Index was outside the bounds of the array for the following line

var resValues = sites.ToDictionary(x => x.Split(',')[2].Replace("test=", ""), 
       x => GetTestCodeename(x.Split(',')[2].Replace("test=", ""), 
          GetTestCode(x.Split(',')[2].Replace("test=", "").Split('_')[1])));

where resValues are of count 1200, so i cannot think of storing in some variable..I want to do for all these 1200 values in single Linq code

Upvotes: 1

Views: 1331

Answers (4)

arekzyla
arekzyla

Reputation: 2898

To avoid an out of bounds exception and null values altogether you can take a monadic approach with SelectMany. Here instead of nulls you will have an empty sequence on which any LINQ function returning enumerable will work without throwing an exception just propagating this empty sequence. Skip and Take also doesn't check for length and return an empty enumerable or some subsequence in case the collection is too short.

var resValues = sites
    .Where(s => s != null)
    .SelectMany(s => s
        .Split(',')
        .Skip(2)
        .Take(1) 
        .Select(a => a.Replace("test=", ""))
        .SelectMany(a => a
            .Split('_')
            .Skip(1)
            .Take(1)
            .Select(b => new
            {
                TestCodeName = GetTestCodeName(a),
                TestCode = GetTestCode(a, b)
            })))
    .ToDictionary(p => p.TestCodeName, p => p.TestCode);

Note that this will ignore all the sites where it couldn't take the values Split(',')[2] or Split('_')[1] in your example.

Upvotes: 1

Ousmane D.
Ousmane D.

Reputation: 56499

a few modifications should help you avoid the index out of bounds exception:

var result = sites.Select(s => s.Split(','))
                  .Where(s => s.Length > 2)
                  .Select(s => s[2].Replace("test=", ""))
                  .ToDictionary(s => s,
                        s => GetTestCodeename(s,
                                 GetTestCode(s.IndexOf('_') != -1 ?
                                        s.Split('_')[1] : string.Empty)));  

or if you don't want to pass an empty string in the case where s.IndexOf('_') != -1 returns false then you can go with this approach:

var result = sites.Select(s => s.Split(','))
                  .Where(s => s.Length > 2)
                  .Select(s => s[2].Replace("test=", ""))
                  .Where(s => s.IndexOf('_') != -1)
                  .ToDictionary(s => s,
                        s => GetTestCodeename(s,
                             GetTestCode(s.Split('_')[1]))); 

Upvotes: 1

Ujwal Neupane
Ujwal Neupane

Reputation: 65

    if(a[1]==null)
   {
     var hasCountTwo= false;
   }
   else{
     var hasCountTwo = true;
   }

Upvotes: 1

xanatos
xanatos

Reputation: 111950

You put some checks here and there :-)

var resValues = (from x in sites
                 let sp1 = x.Split(',')
                 where sp1.Length > 2
                 let rep = sp1[2].Replace("test=", "")
                 let sp2 = rep.Split('_')
                 where sp2.Length > 1
                 select new
                 {
                     Key = rep,
                     Value = GetTestCodeename(rep, GetTestCode(sp2[1]))
                 }).ToDictionary(x => x.Key, x => x.Value);

Note the use of the keyword let to create a variable inside the LINQ expression, then the creation of a new temporary anonymous object containing the Key and Value, then the creation of the Dictionary<,> starting from this object.

I'm skipping all the elements that can't be totally splitted through the two where.

Upvotes: 1

Related Questions