Resolvendo código sem ciclo extra fora do loop
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
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, aint.Parsemenos que você tenha certeza de que será um valor válido; em vez disso, useint.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.WriteAllLinesaceitaIEnumerableisso significa, você pode passar oList<string>diretamente, portanto, não há necessidade de convertê-lo em array.string.Joinpode concatenar umListouArrayem 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));
}
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