Resolved count DataGridView numbers that match Array

titojd

Well-known member
Joined
Oct 12, 2018
Messages
57
Programming Experience
1-3
I have a text file that is generated daily and can contain several lines with 15 numbers drawn from 01 to 25 in each line, the text can have one line or several lines, it changes every day.

I need to compare with an array 'Result' and count how many numbers in each line are equal to the numbers in the array, it's like a raffle, the Text lines are bets, the Array would be the 'Result'

I'm doing it with Dictionary but the result is not what I expected, it's getting like this.
teste.png


I need it to stay like this...
teste2.png


I'm using the following code

C#:
private IDictionary<int, int> GetResultFromTextFile(IEnumerable<int> src)
        {
            var filePath = @"C:\BoaSorte\Banco\testeResultado.txt";
            var delimiter = new[] { ' ' };
            var dict = File.ReadLines(filePath)
                .Where(line => !string.IsNullOrEmpty(line))
                .Aggregate(new Dictionary<int, int>(), (d, line) =>
                {
                    var values = line
                    .Split(delimiter, StringSplitOptions.RemoveEmptyEntries)
                    .Select(x => int.Parse(x));
                    var matchCount = values.Where(v => src.Contains(v)).Count();

                    if (matchCount <= 15)
                    {
                        if (d.ContainsKey(matchCount))
                            d[matchCount]++;
                        else
                            d[matchCount] = matchCount;
                    }
                    return d;
                });

            return dict;
        }



        private void button1_Click(object sender, EventArgs e)
        {
            int outVal;

            if (UltimoResultado.Any(Acertos => !int.TryParse(Acertos.Text, out outVal)))
            {
                MessageBox.Show("Valores Invalidos...");
                return;
            }
            var arr = UltimoResultado.Select(linha => int.Parse(linha.Text));
            var result = GetResultFromTextFile(arr).ToList();
            for (int i = 0; i < result.Count; i++)
            {
                    dgHits.Rows[I].Cells["Acertos"].Value = result[I].ToString();               
            }
        }[/I][/I]
 
Solution
Hello @titojd
As I saw while writting your "raffle" app, it is much easier than what it looked like. As @Skydiver proposes, you need no Dictionary, you don't even need a 2 D array as I thought first. You use a Dictionary when you need a collection of KeyValuePairs that consist in an unique key and its value, for example, the game about translating words. Your job here is just processing lines from a TXT file and adding them to the DataGridView.
In my example, I treated the numbers as strings, because of the prefix zeros (like 05, 08, etc.). I must clarify that if I hadn't read what Skydiver wrote about the Intersect() method, I would have had to write some more code for that logic. So, thank you, Skydiver. What my example...
yes, it's a list, I'm reading how to read a list in json, or get part of the list, I already have the class ListaRateioPremio

C#:
public class ListaRateioPremio
    {
        public string descricaoFaixa { get; set; }
        public int faixa { get; set; }
        public int numeroDeGanhadores { get; set; }
        public double valorPremio { get; set; }
    }
 
For future note, both these links are required reading for anyone who uses HttpClient themselves directly

https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
https://josef.codes/you-are-probabl...-wrong-and-it-is-destabilizing-your-software/

If you don't want to use it directly, and want to make your life easier when downloading stuff, see Flurl - in your case your code for downloading the lotto results would be like await "https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil".GetJsonAsync<LottoRoot>()

--

To parse json easily you copy your JSON, go to app.quicktype.io, set a name for the class, set a namespace, set C#, paste the JSON into the blue area and copy the code out of the white area

This generates you nice classes that are to C# standard naming convention and Just Work to deserialize the data:

1691730324012.png


When using Flurl and QuickType take note to set QuickType to newtonsoft mode, as Flurl doesn't use System.Text.Json. Or, use Flurl to download a string and use the string as per the comments in the QuickType code e.g.

C#:
  var r = LottoRoot.FromJson(await "https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil".GetStringAsync());
 
ps, if you have arrays/lists that a) contain your bought tickets numbers and contain your lotto results, then setting the count of matching numbers is quite easy:

C#:
        var tickets = new []{
          new[] { "01","02","04","05","06","07","09","10","13","14","16","17","19","21","25"},
          new[] { "02","03","04","06","07","08","09","10","13","16","17","19","21","23","25"},
          new[] { "01","02","03","06","07","08","10","11","13","14","16","19","20","23","24"},
          new[] { "02","04","05","07","10","11","12","14","17","18","21","22","23","24","25"},
          new[] { "04","05","07","08","10","11","12","13","16","17","18","20","23","24","25"},
          new[] { "01","02","07","08","10","11","12","14","16","17","18","20","22","23","25"},
          new[] { "03","04","06","07","10","11","12","13","14","16","17","18","22","23","25"}
        };
     
        var result = new[] { "01","02","03","05","06","07","09","10","13","14","16","17","19","21","25" };
     
     
        var ticketsWithCount = tickets.Select(t =>
                t.Concat(new[]{
                    t.Intersect(result).Count().ToString()
                }).ToArray()
            ).ToArray();


This Selects each ticket (an array of numbers) in tickets, and Concats onto the end of the ticket numbers, a new array with just one member; the count of items in the ticket array that Intersect with the lotto result array

Even if you weren't using Intersect (this is very slow, don't do it):

C#:
        var ticketsWithCount = tickets.Select(t =>
                t.Concat(new[]{
                    t.Count(te => result.Contains(te)).ToString()
                }).ToArray()
            ).ToArray();

This is the same as before except the Count is arrived at by doing a "for each number in the ticket, ask the result array if it Contains the number; if the response is true, the result is counted. If not, it isn't"

If this way makes more sense to you, convert the `results` array to a HashSet (call ToHashSet on it and store the retruned value, and use THAT in your Contains. Contains on a HashSet is much faster than on a List/Array )
 
Last edited:
hell, today I see that there is still a lot to read before reaching a programmer environment, thank you very much for giving me this information.
 
Hi @titojd
@cjard 's solution is better than mine, but I tested the code and it works.
The classes:

C#:
namespace WinFormsAppRaffle
{
    public class LotoFacil
    {
        public bool acumulado { get; set; }
        public string dataApuracao { get; set; }
        public string dataProximoConcurso { get; set; }
        public string[] dezenasSorteadasOrdemSorteio { get; set; }
        public bool exibirDetalhamentoPorCidade { get; set; }
        public int? id { get; set; }
        public int indicadorConcursoEspecial { get; set;}
        public string[] listaDezenas { get; set; }
        public string[] listaDezenasSegundoSorteio { get; set; }
        public MunicipioUFGanhadores[] listaMunicipioUFGanhadores { get; set; }
        public RateioPremio[] listaRateioPremio { get; set; }

    }

    public class MunicipioUFGanhadores
    {
        public int ganhadores { get; set; }
        public string municipio { get; set; }
        public string nomeFantasiaUL { get; set; }
        public int posicao { get; set; }
        public string serie { get; set; }
        public string uf { get; set; }
    }

    public class RateioPremio
    {
        public string descricaoFaixa { get; set; }
        public int faixa { get; set; }
        public int numeroDeGanhadores { get; set; }
        public double valorPremio { get; set; }
    }
}
And the code:
C#:
using System.Text.Json;

namespace WinFormsAppRaffle
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string[] lines = File.ReadAllLines(textBox2.Text);
            string[] line, contents, result;
            int count;
            result = LoadResultArray();
            foreach(var num in result)
                textBox1.Text += num + " ";
            for (int i = 0; i < lines.Length; i++)
            {
                contents = lines[i].Split(' ');
                count = contents.Intersect(result).Count();
                line = new string[16];
                for (int j = 0; j < 15; j++)
                    line[j] = contents[j];
                line[15] = count.ToString();
                dataGridView1.Rows.Add(line);
            }
        }

        private string[] LoadResultArray()
        {
            string[] result = null;
            var url = @"https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil";
            HttpClient lotofacil = new HttpClient();
            var response = lotofacil.GetAsync(url).Result;

            if (response.IsSuccessStatusCode)
            {
                var json = response.Content.ReadAsStringAsync().Result;
                var obj = JsonSerializer.Deserialize<LotoFacil>(json);
                result = obj.listaDezenas;
            }
            return result;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.ColumnCount = 16;
            for (int i = 0; i < 15; i++)
            {
                dataGridView1.Columns[i].HeaderText = (i < 9 ? "0" : "") + (i + 1).ToString();
                dataGridView1.Columns[i].Width = 35;
            }
            dataGridView1.Columns[15].HeaderText = "Success";
            dataGridView1.Columns[15].Width = 35;
        }
    }
}
I didn't finish to write the LotoFacil class properties because you don't need them, if you need you can add the missing properties. Also some properties I saw equalized to null I don't know the real type, and I had to guess, maybe in another json they come with some value and it's not the one I wrote, check that.
Again, cjard's solution is better, because as I can see it writes the classes automatically.
But, by now, you have what you needed. You can see the other properties of the LotoFacil object with the Intellisense. It includes the number of winners, that is into an array.
Regards
Pablo
 

Attachments

  • raffle.png
    raffle.png
    8.7 KB · Views: 5
This:
C#:
dataGridView1.Columns[i].HeaderText = (i < 9 ? "0" : "") + (i + 1).ToString();
can be simplified to:
C#:
dataGridView1.Columns[i].HeaderText = $"{i:D2}";
 
This code:
C#:
string[] result = null;
var url = @"https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil";
HttpClient lotofacil = new HttpClient();
var response = lotofacil.GetAsync(url).Result;

if (response.IsSuccessStatusCode)
{
    var json = response.Content.ReadAsStringAsync().Result;
    var obj = JsonSerializer.Deserialize<LotoFacil>(json);
    result = obj.listaDezenas;
}
return result;

can probably be simplified to:
C#:
//$ BUGBUG: Should be declared and initialized static
HttpClient lotofacil = new HttpClient();

try
{
    //$ BUGBUG: This should use await
    var json = lotofacil.GetStringAsync("https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil").Result;
    var obj = JsonSerializer.Deserialize<LotoFacil>(json);
    return obj.listaDezenas;   
}
catch
{
    //$ TODO: Handle errors here
}
//$ REVIEW: Is returning null really a good idea?
return null;
 
I installed the Newtodoft.Json NuGet package to use the way I use it, this code asks me for another using System.Text.Json;
I installed the system.Text.Json, but I don't have the effect, the error continues in (jsom)

C#:
var obj = JsonSerializer.Deserialize<LotoFacil>(json);
 
Olá @titojd
Como eu vi enquanto escrevia seu aplicativo de "sorteio", é muito mais fácil do que parecia. Como @Skydiver propõe, você não precisa de um Dicionário, nem precisa de um array 2D como pensei primeiro. Você usa um Dictionary quando precisa de uma coleção de KeyValuePairs que consistem em uma chave única e seu valor, por exemplo, o jogo sobre tradução de palavras. Seu trabalho aqui é apenas processar linhas de um arquivo TXT e adicioná-las ao DataGridView.
No meu exemplo, tratei os números como strings, por causa dos prefixos zeros (como 05, 08, etc.). Devo esclarecer que se eu não tivesse lido o que o Skydiver escreveu sobre o método Intersect(), eu teria que escrever mais algum código para essa lógica. Então, obrigado, paraquedista. O que meu exemplo faz é ler cada linha do arquivo TXT (você deve escrever o caminho no textBox2), dividindo-o em 15 strings (os números), interseccioná-los com a matriz Result (você deve escrever os números em seu TextBox ( textBox1), separados por 1 espaço, e com o prefixo zeros), e coloque os 15 números e o número de "sucesso" na matriz de strings e, finalmente, adicione essa linha às linhas da grade.
Também gostaria de esclarecer que fui muito ajudado por pessoas (especialmente @cjard) deste Fórum, então acho justo que eu ajude outras pessoas nele, quando puder .
Espero que isso ajude você.
Pablo
O código (veja a imagem também, por favor):
[CÓDIGO=csharp]
namespace WinFormsAppRaffle
{
classe parcial pública Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(remetente do objeto, EventArgs e)
{
string[] linhas = File.ReadAllLines(textBox2.Text);
string[] linha, conteúdo, resultado;
contagem int;
resultado = textBox1.Text.Split(' ');
for (int i = 0; i < linhas.Length; i++)
{
conteúdo = linhas .Split(' ');
contagem = conteúdo.Intersect(resultado).Count();
linha = nova string[16];
para (int j = 0; j < 15; j++)
linha[j] = conteúdo[j];
linha[15] = contagem.ToString();
dataGridView1.Rows.Add(linha);
}

}

private void Form1_Load(remetente do objeto, EventArgs e)
{
dataGridView1.ColumnCount = 16;
para (int i = 0; i < 15; i++)
{
dataGridView1.Columns .HeaderText = (i < 9 ? "0" : "") + (i + 1).ToString();
dataGridView1.Columns .Width = 35;
}
dataGridView1.Columns[15].HeaderText = "Sucesso";
dataGridView1.Columns[15].Width = 35;
}
}
}
[/CÓDIGO]


C#:
 private void Form1_Load(remetente do objeto, EventArgs e)

        {

            dataGridView1.ColumnCount = 16;

            para (int i = 0; i < 15; i++)

            {

                dataGridView1.Columns[i].HeaderText = (i < 9 ? "0" : "") + (i + 1).ToString();

                dataGridView1.Columns[i].Width = 35;

            }

            dataGridView1.Columns[15].HeaderText = "Sucesso";

            dataGridView1.Columns[15].Width = 35;

        }[/CÓDIGO]

@Pablo Como eu faria para colocar o sucesso em primeiro lugar? EX: Sucesso | 01 02 03 ....15[/I][/I][/I]
 
Think something gone wrong with that post, probably you have an array index [i] in your c#, not in a code tag on the forum so it is making everything italic

Anyway, if you're looking to simplify the code, do like I wrote:

Paste the json into QuickType and get the classes
Read the file and turn into a root object
Use LiNQ to turn the root object into an array
Use flurl to retrieve the json and turn into an array
Use the code I put to add the winning counts on the two arrays
Put them to the grid


If I wasn't on a cellphone I'd show you
 

Latest posts

Back
Top Bottom