5

I have the following code:

public class Info
{
  public string Name;
  public string Num;
}

string s1 = "a,b";
string s2 = "1,2";

IEnumerable<Info> InfoSrc =
    from name in s1.Split(',')
    from num in s2.Split(',')
    select new Info()
    {
        Name = name,
        Num = num
    };

List<Info> listSrc = InfoSrc.ToList();

I would like my listSrc result to contain two Info items whose Name and Num properties are:

a, 1
b, 2

However, the code I show above results in four items:

a, 1
a, 2
b, 1
b, 2
2
  • will the splits always be the same length? Commented Nov 12, 2015 at 15:45
  • 3
    Look into Enumerable.Zip. Commented Nov 12, 2015 at 15:48

2 Answers 2

6

You can use Enumerable.Zip:

IEnumerable<Info> InfoSrc = s1.Split(',')
    .Zip(s2.Split(','), (name, num) => new Info(){ Name = name, Num = num });

If you need to map more than two collections to properties you could chain multiple Zip together with an anonymous type holding the second and third:

IEnumerable<Info> InfoSrc = s1.Split(',')
    .Zip(s2.Split(',').Zip(s3.Split(','), (second, third) => new { second, third }),
        (first, x) => new Info { Name = first, Num = x.second, Prop3 = x.third });

Here is a hopefully more readable version:

var arrays = new List<string[]> { s1.Split(','), s2.Split(','), s3.Split(',') };
int minLength = arrays.Min(arr => arr.Length);  // to be safe, same behaviour as Zip
IEnumerable<Info> InfoSrc = Enumerable.Range(0, minLength)
 .Select(i => new Info
 {
     Name = arrays[0][i],
     Num = arrays[1][i],
     Prop3 = arrays[2][i]
 });
Sign up to request clarification or add additional context in comments.

6 Comments

Just to make sure I understand what's going on, basically you split s1 into an array of strings, then Zip that array with another array created from s2. This creates a collection of elements in accordance to whatever the third argument is-- which in this case is the constructor for the Info object. So basically you just get a collection of Info items?
@sab669: yes, but not a collection. Currently it's just a query. If you want a collection you need to append ToList or ToArray. Enumerable.Zip enumerates two sequences simultaneously and returns the items which are at the same index.
What happens when I need three split strings of equal size? Info now has 3 fields. string s1 = "a,b"; string s2 = "1,2"; string s3 = "G,J";
I more so meant collection is just the "generic" English term that you have a bunch of objects. But technically speaking, I guess I'm not 100% certain on the differences between the Collection / ICollection class + interface versus IEnumerable. Not sure when to use one or the other.
@user3716892 You should just be able to zip InfoSrc and s3 together again and then assign that third property? I'm sure Tim has a better solution though. Zip says that the first and second arguments don't have to be of the same type so it shouldn't be an issue.
|
5

Assuming that the number of items in each list is equal, it looks like you're trying to Zip them together...

s1.Split(',').Zip(s2.Split(','), (name, num) => new Info{Name = name, Num = num})

1 Comment

Should be: IEnumerable<Info> InfoSrc = s1.Split(',').Zip(s2.Split(','), (a, b) => new Info { Name = a, Num = b });

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.