Resolvendo código sem ciclo extra fora do loop

Oct 09 2020

Este código lê o diâmetro e a altura do barril do arquivo, então, com base na dimensão, tome decisões e, finalmente, essas decisões são impressas em um arquivo. Meu pronbelm é como evitar o uso do código escrito nas linhas 70-101? Provavelmente tem a ver com a linha 35, mas ainda não descobri como contorná-la. Seria bom se houvesse uma maneira (chance) de tornar este código mais curto.

PS d - diâmetro, h - altura

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
     
    namespace TaaviSimsonTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Reads values from an input file
                var numbersList = File.ReadAllLines("C:\\temp\\vaaditest07.txt")
                    .Select(line => line.Split(' '))
                    .Select(barrels => new
                    {
                        diameter = int.Parse(barrels[0]),
                        height = int.Parse(barrels[1])
                    })
                    .ToArray();
     
                //Puts diameter and height values to arrays
                int[] d = numbersList.Select(x => x.diameter).ToArray();
                int[] h = numbersList.Select(x => x.height).ToArray();
     
                //Displays numbersList with line number, diameter and height
                for (int i = 0; i < d.Length; i++)
                {
                    Console.WriteLine("Line {0}: diameter: {1}, height: {2}", 
                        i, d[i], h[i]);
                }
     
                //comparing barrel sizes and making a decision
                List<string> output = new List<string>();
                for (int j = 0; j < (d.Length - 1); j++)
                {
                    int a = j + 1;
                    int b = j + 2;
                    if (d[j] > d[j + 1] && h[j] > h[j+1])
                    {
                        string command = a + "<-" + b;  //1 <- 2, if j = 0
                        output.Add(command);            //puts command in array
                    }
                    else if (d[j] < d[j + 1] && h[j] < h[j+1])
                    {
                        string command = a + "->" + b;
                        output.Add(command);
                    }
                    else if (d[j+1] < h[j] &&       
                        ((d[j+1] * d[j+1] + h[j+1] * h[j+1]) <
                        d[j] * d[j]))
                    {
                        string command = a + "<-" + b;  // 2 <- 3
                        output.Add(command);
                    }
                    else if(d[j] < h[j+1] &&    
                        ((d[j] * d[j] + h[j] * h[j]) <
                        d[j+1] * d[j+1]))
                    {
                        string command = a + "->" + b;
                        output.Add(command);
                    }
                    else
                    {
                        string command = a + "--" + b;
                        output.Add(command);
                    }
                }
     
                //how to avoid this cycle?
                int c = 1;
                int e = d.Length;
                if (d[0] > d[d.Length - 1] && h[0] > h[d.Length - 1])    
                {
                    string command = c + "<-" + e;
                    output.Add(command);
                }
                else if (d[0] < d[d.Length - 1] && h[0] < h[d.Length-1])  
                {
                    string command = c + "->" + e;
                    output.Add(command);
                }
                else if (d[d.Length-1] < h[0] && 
                    ((d[d.Length-1] * d[d.Length-1] + h[d.Length-1] * h[d.Length-1]) < 
                    d[0] * d[0]))
                {
                    string command = c + "<-" + e;
                    output.Add(command);
                }
                else if (d[0] < h[d.Length-1] &&    
                    ((d[0] * d[0] + h[0] * h[0]) <  
                    d[d.Length-1]*d[d.Length-1]))
                {
                    string command = c + "->" + e;
                    output.Add(command);
                }
                else
                {
                    string command = c + "--" + e;
                    output.Add(command);
                }
     
                //Writes values of array to a new file
                String[] outputlist = output.ToArray();
                File.WriteAllLines(@"C:\Temp\barrelsOutput.txt", outputlist);
                //Displaying output in console
                Console.WriteLine("");
                foreach (var item in outputlist)
                {
                    Console.WriteLine(item.ToString());
                }
            }
        }
    }

Respostas

11 iSR5 Oct 09 2020 at 03:00

Algumas notas :

  • você deve tornar seu código mais legível com mais frequência. Isso daria ao seu código mais sentido até para você mesmo, especialmente se você o revisasse no futuro.
  • você precisa considerar a convenção de nomenclatura como usar Pascal Casing para propriedades, nomeando suas variáveis ​​com nomes significativos.
  • Não divida a string sem validar primeiro.
  • Não use Parsevalores diretamente como, a int.Parsemenos que você tenha certeza de que será um valor válido; em vez disso, use int.TryParsepara evitar exceções.
  • Não crie um array de tipo anônimo (ou qualquer outro tipo), a menos que seja necessário (no seu caso, não é necessário) em vez disso, use o array que você criou.
  • Sempre que você vir alguma redundância em seu código (código repetitivo), mova-o para um método, desta forma você pode reutilizar o método e seus ajustes estariam em um só lugar.
  • File.WriteAllLinesaceita IEnumerableisso significa, você pode passar o List<string>diretamente, portanto, não há necessidade de convertê-lo em array.
  • string.Joinpode concatenar um Listou Arrayem um, stringentão use isso a seu favor.
  • Sempre valide seus valores o máximo possível, isso daria mais estabilidade ao seu código e garantiria seus resultados.

Sua pergunta sobre esta parte do código:

if (d[0] > d[d.Length - 1] && h[0] > h[d.Length - 1])    
{
    string command = c + "<-" + e;
    output.Add(command);
}
else if (d[0] < d[d.Length - 1] && h[0] < h[d.Length-1])  
{
    string command = c + "->" + e;
    output.Add(command);
}
else if (d[d.Length-1] < h[0] && 
    ((d[d.Length-1] * d[d.Length-1] + h[d.Length-1] * h[d.Length-1]) < 
    d[0] * d[0]))
{
    string command = c + "<-" + e;
    output.Add(command);
}
else if (d[0] < h[d.Length-1] &&    
    ((d[0] * d[0] + h[0] * h[0]) <  
    d[d.Length-1]*d[d.Length-1]))
{
    string command = c + "->" + e;
    output.Add(command);
}
else
{
    string command = c + "--" + e;
    output.Add(command);
}

Esta parte precisa ser movida para um método e torná-la mais generalizada para ser reutilizada, assim:

private static string GetCommand(int currentDiameter , int nextDiameter , int currentHeight , int nextHeight)
{
    var currentDiameterMultiplied = currentDiameter * currentDiameter;
    var nextDiameterMultiplied = nextDiameter * nextDiameter;
    var currentHeightMultiplied = currentHeight * currentHeight;
    var nextHeightMultiplied = nextHeight * nextHeight;

    if(currentDiameter > nextDiameter && currentHeight > nextHeight)
    {
        return "<-";
    }

    if(currentDiameter < nextDiameter && currentHeight < nextHeight)
    {
        return "->";
    }

    if(nextDiameter < currentHeight && ( ( nextDiameterMultiplied + nextHeightMultiplied ) < currentDiameterMultiplied ))
    {
        return "<-";
    }

    if(currentDiameter < nextHeight && ( ( currentDiameterMultiplied + currentHeightMultiplied ) < nextDiameterMultiplied ))
    {
        return "->";
    }

    return "--";
}

agora você pode reutilizá-lo em seu código, aqui está a versão modificada de seu código:

static void Main(string[] args)
{
    //Reads values from an input file
    var path = "C:\\temp\\vaaditest07.txt";
    
    if(!File.Exists(path)) { throw new FileNotFoundException(nameof(path)); }
        
    var data = File.ReadAllLines(path); 
    
    if(data == null) { throw new ArgumentNullException(nameof(data)); }
    
    var numbersList = data
                        .Select(line => 
                            line.Split(' ')
                                .Select(barrels => new
                                {                       
                                    Diameter = int.TryParse(barrels[0], out var diameter) ? diameter : 0,
                                    Height = int.TryParse(barrels[1], out var height) ? height : 0
                                }).ToArray();

    //comparing barrel sizes and making a decision
    var output = new List<string>();

    var length = numbersList.Length;
    
    var command = string.Empty;
    
    for(int index = 0, nextIndex = 1; index < length; index++, nextIndex++)
    {  
        var current = numbersList[index];
        
        var next = numbersList[nextIndex];

        // Displays numbersList with line number, diameter and height
        Console.WriteLine("Line {0}: diameter: {1}, height: {2}" , index , current.Diameter , current.Height);

        if(index != length - 1)
        {   
            var commandSymbol = GetCommand(current.Diameter , next.Diameter , current.Height , next.Height);
            command = $"{nextIndex}{commandSymbol}{nextIndex + 1}"; } else { var commandSymbol = GetCommand(numbersList[0].Diameter , current.Diameter , numbersList[0].Height , current.Height); command = $"{0}{commandSymbol}{length}";                
        }
        
        output.Add(command);
    }
    
    // Writes values of array to a new file
    File.WriteAllLines(@"C:\Temp\barrelsOutput.txt" , output);

    //Displaying output in console
    Console.WriteLine();
    Console.WriteLine(string.Join(Environment.NewLine, output));
}

 
DaveyvanTilburg Oct 09 2020 at 01:53

Eu aconselharia começar escrevendo um código que seja realmente legível. Também pela sua pergunta, eu realmente não sei qual é o seu objetivo.

Você quer um código curto que faça o trabalho? Então eu diria que você já está lá. Se você deseja um código legível e sustentável, tente uma abordagem OO, em que você encapsula pedaços de código em objetos que, com seus nomes e métodos, documentam o que realmente está fazendo.

Porque estou muuuuito com preguiça de interpretar o que você está tentando fazer nas linhas 70-101. Eu quero ler os nomes e títulos e saber disso.

Então, esses são meus dois centavos