Improve Performance Nested Foreachs

3

I have 2 foreach nested of a class articles, in which I go through two lists, and if the item in list 1 is in list 2, it must do a couple of operations, the dilemma is that when dealing with very long lists, it takes a long time and I need to improve that time.

Code:

foreach (Articulo x in Articulos) //Lista Principal
{
  foreach(Articulo y in listSec)
  {
    if (y.Art_CodGen == x.Art_CodGen) //Si son Iguales 
    {
      if (y.Precios[0] != x.Precios[i]) //Y tienen distinto precio
      {
        updatedRows += UpdateArticulo(x, i); // Actualizo
      }
    }
   }                                                                         
 }
    
asked by FederHico 04.07.2017 в 04:10
source

3 answers

2

The detail that I see in your code is that for each item in list 1 you are going through completely list 2, because your if what it does is identify that they are equal in the Art_CodGen and that they are of different price, to finally update, this does not stop the foreach of the list 2 and continues iterating objects as well as it continues evaluating and affecting the performance of the application. I will leave you the fragment of code that I occupy in these cases and I explain it to you in detail below:

  foreach (persona pItem in lista1)
            {
                persona perAux = lista2.FirstOrDefault(x => x.Codigo == pItem.Codigo);

                if (perAux != null)
                {
                    //Actualizas
                    Console.WriteLine("La persona: " + perAux.Nombre + " esta en la lista dos");
                }
            }

Now I explain the scenario you set, I have defined a person-type object with two attributes, you know to simplify things:

 public class persona
        {
            public int Codigo { get; set; }
            public string Nombre { get; set; }
        }

Two person type lists are created:

 List<persona> lista1 = new List<persona>();
 List<persona> lista2 = new List<persona>();

Objects are added to the list where, eye three of the people will be on both lists ( Katz , Manuel y Uriel ).

//Personas que iran en la lista 1
            persona p1 = new persona() { Codigo = 1,Nombre="Katz" };
            persona p2 = new persona() { Codigo = 2, Nombre = "Katz" };
            persona p3 = new persona() { Codigo = 3, Nombre = "Arturo" };
            persona p4 = new persona() { Codigo = 4, Nombre = "Moises" };
            persona p5 = new persona() { Codigo = 5, Nombre = "Manuel" };
            persona p6 = new persona() { Codigo = 6, Nombre = "Uriel" };

            lista1.Add(p1);
            lista1.Add(p2);
            lista1.Add(p3);
            lista1.Add(p4);
            lista1.Add(p5);
            lista1.Add(p6);

            //Personas que iran en la lista 2
            persona p7 = new persona() { Codigo = 1, Nombre = "Katz" };
            persona p8 = new persona() { Codigo = 5, Nombre = "Manuel" };
            persona p9 = new persona() { Codigo = 6, Nombre = "Uriel" };
            persona p10 = new persona() { Codigo = 7, Nombre = "Ana" };
            persona p11 = new persona() { Codigo = 8, Nombre = "Rosa" };
            persona p12 = new persona() { Codigo = 9, Nombre = "Luisa" };

            lista2.Add(p7);
            lista2.Add(p8);
            lista2.Add(p9);
            lista2.Add(p10);
            lista2.Add(p11);
            lista2.Add(p12);

Once the scenario has been defined, if I explain the code to you, a single foreach is made that goes through the person objects in the first list, inside the foreach of the first list an auxiliary person object is created, now this is the part where you should pay attention:

lista2.FirstOrDefault(x => x.Codigo == pItem.Codigo);

A search is performed using the function FirstOrDegault and a lambda expression (very useful) where it is evaluated that the code (ID) of the pItem object in list 1 is in list two:

x => x.Codigo == pItem.Codigo

If you find someone like them in list 2, the perAux object will not be null and you can also do your other if (the price one), because the perAux is the one that you extracted from the list 2 and the pItem is the one from the list 1 that is, you have the two objects for Do the logic you require .

 foreach (persona pItem in lista1)
                {
                    persona perAux = lista2.FirstOrDefault(x => x.Codigo == pItem.Codigo);

                    if (perAux != null)
                    {
                        //Actualizas
                        Console.WriteLine("La persona: " + perAux.Nombre + " esta en la lista dos");
                    }
                }

This is the output of the program.

La persona: Katz esta en la lista dos
La persona: Manuel esta en la lista dos
La persona: Uriel esta en la lista dos
    
answered by 04.07.2017 / 08:31
source
2

If you want to improve the performance you can use Thread or ForEach asynchronous to go through them more quickly. One way to implement this operation would be with the function Parallel.ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body);

Also, in the second search you could use Linq to only search for the ones you need to go through (although it is a search but more optimized).

An example of the implementation of this solution would be something like this:

Parallel.ForEach(Articulos, RecorrerSegunda);

public void RecorrerSegunda(Articulo art)
{
        var articulos = listSec.Where(c => c.Art_CodGen == art.Art_CodGen && c.Precios[0] == art.Precios[i]);
        Parallel.ForEach(articulos, new Action<Articulo>(
            (a) =>
            {
                lock(art)
                {
                    UpdateArticulo(art, i);
                }
            }));
}
    
answered by 04.07.2017 в 09:24
1

You can apply the binary search. I explain the idea:

  • you divide the set into 2 subsets,
  • you search in each of the 2 subsets,
  • verify by comparing if it is smaller or bigger,
  • through that comparison you choose a subset,
  • with the new subset, you re-split into 2 subsets, and you're repeating the algorithm.

Advantages:

You are always dividing the set and you choose the set in which your object can surely be.

Example:

  • searched: 5
  • set {12,5, 1 , 4, 49, 89}
  • ordering 5 {1,4,5,12,49,89}
  • 5 {1,4,5}{12,49,89}
  • 1 is less than 5, so 5 may yes
  • this in the 1st subset, 49 is the first element of the second set, and 49 is greater than 5 therefore 5 is not found in the second subset.

  • second iteration {1,4,5}

    • and so on ...
answered by 04.07.2017 в 05:14