Morphed
Morphed

Reputation: 3619

Create duplicate items in a list

I have the following code to duplicate the members of a list X times.

Although it works it doesn't feel particularly clean.

Live code example: http://rextester.com/UIVZVX7918

public static List<ServiceEndPoint> GetServiceEndPoints()
{
    const string source = "http://webSiteA.asmx,http://webSiteB.asmx";
    const int instances = 3;

    var splitEndPoints =  source.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries)
                                    .Select((s, i) => new ServiceEndPoint
                                                                {
                                                                    Index = i,
                                                                    Uri = s
                                                                })
                                                                .ToList();

    // Duplicate the contents of splitEndPoints "instances" number of times
    var serviceEndPoints = new List<ServiceEndPoint>();
    foreach (var point in splitEndPoints)
    {
        for (var i = 0; i < instances; i++)
        {
            serviceEndPoints.Add(point);
        }
    }

    return serviceEndPoints;
}

public class ServiceEndPoint
{
    public int Index { get; set; }
    public string Uri { get; set; }
}

Is there a better way of doing it?

Upvotes: 9

Views: 15291

Answers (3)

Jim Mischel
Jim Mischel

Reputation: 134125

Perhaps something along the lines of:

var serviceEndPoints = splitEndPoints.SelectMany(t =>
    Enumerable.Repeat(t, instances)).ToList();

That will give you "A,A,A,B,B,B,C,C,C". If you want "A,B,C,A,B,C,A,B,C":

var serviceEndPoints = Enumerable.Repeat(
    splitEndPoints, instances).SelectMany(t => t).ToList();

Upvotes: 23

p.s.w.g
p.s.w.g

Reputation: 149068

You can do this with a little Linq:

int instances = 3;
var serviceEndPoints = 
    (from e in Enumerable.Range(0, instances)
     from x in serviceEndPoints
     select x)
    .ToList();

Or if you prefer fluent syntax:

var serviceEndPoints = Enumerable
    .Range(0, instances)
    .SelectMany(e => serviceEndPoints)
    .ToList();

Note that given a list like { A, B, C } will produce a list like { A, B, C, A, B, C, A, B, C }. If you want to produce a list like { A, A, A, B, B, B, C, C, C }, you can simply reverse the order of the collections:

var serviceEndPoints = 
    (from x in serviceEndPoints
     from e in Enumerable.Range(0, instances)
     select x)
    .ToList();

Or in fluent syntax:

var serviceEndPoints = serviceEndPoints
    .SelectMany(x => Enumerable.Range(0, instances), (x, e) => x)
    .ToList();

Upvotes: 11

xanatos
xanatos

Reputation: 111940

Splitting the two components...

var parts = source.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);

var serviceEndPoints = (from i in Enumerable.Range(0, instances * parts.Length)
                        let j = i / instances
                        let part = parts[j]
                        select new ServiceEndPoint { Index = j, Uri = part }).ToList();

or...

var parts = source.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);

var serviceEndPoints2 = (from i in Enumerable.Range(0, parts.Length)
                        let part = parts[i]
                        from j in Enumerable.Range(0, instances)                            
                        select new ServiceEndPoint { Index = i, Uri = part }).ToList();

It's very similar to two for one inside the other :-)

Upvotes: 2

Related Questions