Aht
Aht

Reputation: 593

Faster way to convert data fome one list to other

I need to convert data from one list to another. I need my code to look exactly like that ( just a requirement that i must complete) :

public interface IHuman
{
        string name { get; set; }
        string lastName { get ;set; }
        int age { get; set; }
}

And I have 2 other classes :

public class HumanA : IHuman
{
    //Implementation
}

public class HumanB : IHuman
{
    //Implementation
}

In my program I have that part:

List<HumanA> listA = some data

I need to write data from the list of HumanA to the list of HumanB it must be this list no other composition.

Is there a simpler way to do this than :

list<HumanB> listB = listA.ConverAll(x => new HumanA()
{
    name = x.name,
    lastName = x.lastName,
    age = x.age
});

?

It should be because HumanA and HumanB have only property implements from IHuman but I can't use:

list<IHuman>

Upvotes: 0

Views: 175

Answers (4)

AndyT
AndyT

Reputation: 176

It is unclear why you have to have your code look exactly like you do, as you say.

As you are implementing the interface you can actually use the code below to get the same result. Effectively HumanA and HumanB are the same because of the Interface so you can do the below and define listA and listB as a list of IHuman then add HumanA's to the list.

        var listA = new List<IHuman>();

        listA.Add(new HumanA());
        listA.Add(new HumanA());
        listA.Add(new HumanA());

        var listB = new List<IHuman>(listA);

        var humanB = (HumanB)listB[0];

The last CAST line isn't actually required as the class implements all the same methods as the HumanA class, because of IHuman, unless HumanB had extra methods, then the cast would be required to access those methods.

Upvotes: 0

Bongo
Bongo

Reputation: 3153

Nitram gave you a very good answer so I can't provide any more helpfull answer with regards to working code. BUT

I wrote a little test so that you can see for yourself what works and how subtile the differences are.

A little clarification on the Tests.

  1. The List I used contains 10000 Elements.
  2. Every Test is ran 10 times.
  3. The code I tested was mostly provided by the answers in this question

Here the Code:

static void Main(string[] args)
{
    //Creation
    List<HumanA> listA = new List<HumanA>();
    for (int j = 0; j < 2000; j++)
    {
        listA.Add(new HumanA());
        listA.Add(new HumanA());
        listA.Add(new HumanA());
        listA.Add(new HumanA());
        listA.Add(new HumanA());
    }

    Stopwatch stop = new Stopwatch();
    List<HumanB> listB = null;

    int roundsToComplete = 10;

    long testTime1 = 0;
    long testTime2 = 0;
    long testTime3 = 0;
    long testTime4 = 0;
    long testTime5 = 0;
    long testTime6 = 0;


    long testTime1ms = 0;
    long testTime2ms = 0;
    long testTime3ms = 0;
    long testTime4ms = 0;
    long testTime5ms = 0;
    long testTime6ms = 0;

    for (int rounds = 0; rounds < roundsToComplete; rounds++)
    {
        //Test 1
        stop.Start();
        listB = new List<HumanB>();
        foreach (HumanA humanA in listA)
        {
            HumanB humanB = new HumanB();
            humanB.age = humanA.age;
            humanB.name = humanA.name;
            humanB.lastName = humanA.lastName;
            listB.Add(humanB);
        }
        stop.Stop();
        testTime1 += stop.ElapsedTicks;
        testTime1ms += stop.ElapsedMilliseconds;
        listB.Clear();
        listB = null;
        stop.Reset();

        //Test 2
        stop.Start();
        listB = new List<HumanB>();
        foreach (HumanA humanA in listA)
        {
            HumanB humanB = new HumanB(humanA);
            listB.Add(humanB);
        }
        stop.Stop();
        testTime2 += stop.ElapsedTicks;
        testTime2ms += stop.ElapsedMilliseconds;
        listB.Clear();
        listB = null;
        stop.Reset();

        //Test 3
        stop.Start();
        listB = listA.ConvertAll(x => new HumanB(x));
        stop.Stop();
        listB.Clear();
        listB = null;
        testTime3 += stop.ElapsedTicks;
        testTime3ms += stop.ElapsedMilliseconds;

        //Test 4
        stop.Start();
        int count = listA.Count;
        listB = new List<HumanB>();
        for (int i = 0; i < count; i++)
        {
            listB.Add(new HumanB(listA[i]));
        }

        stop.Stop();
        listB.Clear();
        listB = null;
        testTime4 += stop.ElapsedTicks;
        testTime4ms += stop.ElapsedMilliseconds;

        //Test 5
        stop.Start();
        listB = listA.Select(x => new HumanB() { name = x.name, lastName = x.lastName, age = x.age }).ToList();
        stop.Stop();
        listB.Clear();
        listB = null;
        testTime5 += stop.ElapsedTicks;
        testTime5ms += stop.ElapsedMilliseconds;


        //Test6
        stop.Start();
        count = listA.Count;
        listB = new List<HumanB>(count);
        Parallel.For(0, count, c=>
        {
            listB.Add(new HumanB(listA[c])); 
        });
        stop.Stop();
        listB.Clear();
        listB = null;
        testTime6 += stop.ElapsedTicks;
        testTime6ms += stop.ElapsedMilliseconds;


    }

    Console.WriteLine("1: " + testTime1 / roundsToComplete);
    Console.WriteLine("2: " + testTime2 / roundsToComplete);
    Console.WriteLine("3: " + testTime3 / roundsToComplete);
    Console.WriteLine("4: " + testTime4 / roundsToComplete);
    Console.WriteLine("5: " + testTime5 / roundsToComplete);
    Console.WriteLine("6: " + testTime6 / roundsToComplete);

    Console.WriteLine("milliseconds 1: " + testTime1ms / roundsToComplete);
    Console.WriteLine("milliseconds 2: " + testTime2ms / roundsToComplete);
    Console.WriteLine("milliseconds 3: " + testTime3ms / roundsToComplete);
    Console.WriteLine("milliseconds 4: " + testTime4ms / roundsToComplete);
    Console.WriteLine("milliseconds 5: " + testTime5ms / roundsToComplete);
    Console.WriteLine("milliseconds 6: " + testTime6ms / roundsToComplete);

    Console.ReadLine();

}

And here are the results in ticks and millisenconds

1: 24944
2: 4278
3: 2746
4: 5003
5: 9230
6: 21502
milliseconds 1: 12
milliseconds 2: 1
milliseconds 3: 0
milliseconds 4: 2
milliseconds 5: 4
milliseconds 6: 10

Upvotes: 2

Nitram
Nitram

Reputation: 6716

If you want a faster way in matters of runtime you want to avoid any overhead by linq and focus as best as possible to limit the operations required.

This means you want to avoid:

  • The creation of a iterator
  • The creation of any lambda function
  • Resizing of the storage array of the List-Object

So you want to use a for-loop to fetch your objects so you don't have any iterator object and you want to create the new list with the specified capacity so it does not have to resize. Also you want to set the properties required using the constructor arguments.

And aside from the creation of the lambda function (that is used as converter) this is exactly the same what the ConvertAll-function does. So you will not get anything that is much faster than this.

If you want to get some easier code, suggest you implement a constructor that takes the IHuman interface in both classes and copy the data there. So you can reduce the code to something like:

List<HumanB> listB = listA.ConvertAll(x => new HumanB(x));

EDIT: In case we are talking about massively large lists and objects that take a rather long time to create there is also the possibility to use multiple threads to speed things up. But for the simple example you provided I highly doubt that this will do anything but make things slower and more complicated to read in your case.

Upvotes: 2

jdweng
jdweng

Reputation: 34421

Try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<HumanA> aS = new List<HumanA>();

            List<HumanB> bS = aS.Select(x => new HumanB() { name = x.name, lastName = x.lastName, age = x.age }).ToList(); 
        }
    }
    public class IHuman
    {
        public string name { get; set; }
        public string lastName { get ;set; }
        public int age { get; set; }
    }
    public class HumanA : IHuman
    {
    //Implementation
    }
    public class HumanB : IHuman
    {
       //Implementation
    }

}
​

Upvotes: -3

Related Questions