Resolved count DataGridView numbers that match Array

titojd

Well-known member
Joined
Oct 12, 2018
Messages
63
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...
Is there any particular reason why you need to do everything using LINQ extension methods?

Anyway, the key LINQ extension method you want to take advantage of is https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.intersect?view=net-7.0. Once that returns an enumberable with the intersecting items, just call Count() on that enumerable to find out how many numbers match.
 
I managed to solve half of the problem, but a result appears for each line, the repeated lines in the number of hits only one appears, the others are empty,

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));
                    int matchCount = values.Intersect(src).Count();

                        if (matchCount <= 15) { d[matchCount] = matchCount; }

                    return d;
                });

            return dict;
        }
C#:
 for (int i = 0; i < result.Count; i++)
            { dgHits.Rows[i].Cells["Acertos"].Value = result[i].Value;}
 
Last edited by a moderator:
Why would you expect a different result given this line of code?
C#:
if (matchCount <= 15) { d[matchCount] = matchCount; }
You are making a dictionary were the key is the value, and the value happens to be the match count.

And then later, you are trying to pull values from that dictionary assuming that the key is the row number in the second of chunk of code you have above.

Why do you even need to use a dictionary?

I'm assuming that you are reading from your text file twice: once to get the values and put into the grid, and a second time in that first chunk of code you have above. Why? Why count the matches as each line is read from the file and populate the data grid with the read values from the file and the match count at the same time?
 
Hello Paratrooper, thank you very much for answering.
you are right in the analysis, I was actually reading it twice,
in fact, I've done and re-done this code so many times that I've already messed with my head,
following your guidance, my code is like this now,
C#:
 private IDictionary<int, int> GetResultFromTextFile(IEnumerable<int> src)
        {
            var filePath = @"C:\BoaSorte\Banco\testeResultado.txt";
            var delimiter = new[] { ' ' };
            var dict = new Dictionary<int, int>();

            foreach (var line in File.ReadLines(filePath).Where(line => !string.IsNullOrEmpty(line)))
            {
                var values = line.Split(delimiter, StringSplitOptions.RemoveEmptyEntries)
                                 .Select(x => int.Parse(x));
                var matchCount = values.Count(v => src.Contains(v));

                if (matchCount <= 15)
                {
                    if (!dict.ContainsKey(matchCount))
                    {
                        dict[matchCount] = matchCount;                                             
                    }

                    //dict[matchCount]++;
                }
            }
            return dict;
        }
[/ICODE]
[ICODE]
    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(Rows => int.Parse(Rows.Text));
            var result = GetResultFromTextFile(arr).ToList();

            for (int i = 0; i < result.Count; i++)
            {
                dgHits.Rows[i].Cells["Acertos"].Value = result[i].Value;
            }
        }
this is how it is showing on the grid

chaverepetida.png


I need to show how many hits are in each line, comparing with the numbers generated in the array,
EX: line 1 --- 10 hits,
line2 --- 8 hits,
row 3 --- 10 hits,
line 4 --- 11 hits,
line 5 --- 11 hits,
row 6 --- 7 hits.

the code I have, shows me the total lines with 10 hits,
the total lines with 11 hits,
the total rows with 7 hits, Just exemplifying
*that's not what I need.
what i need each line to have the number of hits at the end of the line itself.
I'll leave an image to try to understand.
so it would have to stay
teste2.png

doesn't have to be in order
I'm not being able to make this happen...
 
Last edited by a moderator:
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 does is, read each line from the TXT file (you have to write the path in the textBox2), split it into 15 strings (the numbers), Intersect them with the Result array (you have to write the numbers in its TextBox (textBox1), separated by 1 space, and with the prefix zeros), and put the 15 numbers and the "success" number in the string array, and finally add that line to the grid's rows.
I would also like to clarify that I have been helped very much by people (especially @cjard) from this Forum, so I think it is fair that I help other people in it, when I can.
I hope this helps you.
Pablo
The code (see the image too, please):
C#:
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 = textBox1.Text.Split(' ');
            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 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;
        }
    }
}
 

Attachments

  • raffle.png
    raffle.png
    8.7 KB · Views: 18
Solution
hello @Pablo, I am happy with your answer, thank you very much.
it worked as well as in the image, however, my Result comes on an array
Label[ ] ResultUltimat = new Label[15] created dynamically, where Array ' ResultUltimat' is populated by a json file received via url.

how would I replace this TextBox1.Text with the ResultUltimat[ ].Text?
tried my way here but it just returned zeros on every line
 
You shouldn't use an array of Label objects, you use them only to show a readonly text in the Form. You should use directly an array of string to load the numbers from the json file. And then if you want to show the numbers from the Result array in Labels, you create the array of Label and pass the numbers to their Text property. I suppose you'll not have problems retrieving the numbers as strings, but if you do, you can show me that json file and I will see. Probably, beyond the very very bad code of the array of Label, you are reading the json file incorrectly.
 
so I load my Label array with json
C#:
 private void CarregaResultado()
        {
            var url = @"https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil";
            HttpClient lotefacil = new HttpClient();
            var resposta = lotofacil.GetAsync(url).Result;

            if (resposta.IsSuccessStatusCode)
            {
                var listaDezenas = resposta.Content.ReadAsStringAsync().Result;
                var listaDezenass = JsonConvert.DeserializeObject<Resultado>(listaDezenas);

                Control[] controles = ResultUltimat;

                for (int i = 0; i < controles.Length; i++)
                {
                    int valor = Convert.ToInt32(listaDezenass.listaDezenas[I]);
                    controles[I].Text = valor.ToString("D2");
                }
            }
            if (resposta.IsSuccessStatusCode)
            {
                var numero = resposta.Content.ReadAsStringAsync().Result;
                var sorteio = JsonConvert.DeserializeObject<Resultado>(número);

                txtConcurso.Text = sorteio.numero.ToString();
                lblData.Text = sorteio.dataApuracao.ToString();
            }
        }
 
Last edited by a moderator:
@titojd : When posting long blocks of code, please use code tags ([code]...[/code]) instead of the inline code tags ([icode]...[/icode]). Code tags can easily be invoked by using the button that looks like </> on the toolbar. It looks like you have been using the inline code tags button: >_.
 
Anyway, part of the issue here is that you are using your UI as your data model. You are storing the values you got from the web service into UI controls instead of just holding on to your Resultado object. If you just hold on to that object, then you would simply use:
C#:
count = contents.Intersect(resultado.listaDezenas).Count();

As an side, a few other things not directly related to your problem:
1) You are using HttpClient incorrectly. You should only create one static instance and use it for the lifetime of your application.
2) Lines 7-10 and 20-23 are essentially the same. Why not just combine the two chunks of code?
3) Do you really need the variable controles?
4) You should really avoid using var result = CallSomeMethodAsync().Result. The correct thing to do is to write var result = await CallSomeMethodyAsync(). The former is synchronous and can make your UI non-responsive if you are calling the code in your UI thread, or just monopolizes a thread if you are not using the UI thread. The latter is asynchronous and makes your UI seem more responsive if calling the code in your UI thread, or allows the CPU to context switch to another thread if you are not using the UI thread.
 
Last edited:
I want to thank @Paraquedista and @Pablo,
Thank you so much,
It was a great help, I was lost on the way for days,
A big hug and stay with God.
 
You solved the issue about the Result array and the json? If not, if you give me the string you get from it (like if it was a TXT file) I will probably get the way to obtain the numbers (string) array.
 
the way I found was to load it together with the json file and call it by loading the form

C#:
private void CarregaResultado()
        {
            var url = @"https://servicebus2.caixa.gov.br/portaldeloterias/api/lotofacil";
            HttpClient lotofacil = new HttpClient();
            var resposta = lotofacil.GetAsync(url).Result;

            if (resposta.IsSuccessStatusCode)
            {
                var listaDezenas = resposta.Content.ReadAsStringAsync().Result;
                var listaDezenass = JsonConvert.DeserializeObject<Resultado>(listaDezenas);

                Control[] controles = UltimoResultado;

                for (int i = 0; i < controles.Length; i++)
                {
                    int valor = Convert.ToInt32(listaDezenass.listaDezenas[i]);
                    controles[i].Text = valor.ToString("D2");
                }
                //this part loads bets and shows hits
                string[] lines = File.ReadAllLines(@"C:\BoaSorte\Banco\testeResultado.txt");
                string[] line, contents;
                int count;
                //result = TextBox1.Text.Split();
                for (int i = 0; i < lines.Length; i++)
                {
                    contents = lines[i].Split(' ');
                    count = contents.Intersect(listaDezenass.listaDezenas).Count();
                    line = new string[16];
                    for (int j = 0; j < 15; j++)
                        line[j] = contents[j];
                    line[15] = count.ToString();
                    dgHits.Rows.Add(line);
                }
            }
            if (resposta.IsSuccessStatusCode)
            {
                var numero = resposta.Content.ReadAsStringAsync().Result;
                var sorteio = JsonConvert.DeserializeObject<Resultado>(numero);

                txtConcurso.Text = sorteio.numero.ToString();
                lblData.Text = sorteio.dataApuracao.ToString();
//lblGanhadores.Text = sorteio.numeroDeGanhadores.ToString();
            }
        }
I couldn't load the lblGanhadores.Text = sorteio.numeroDeGanhadores.ToString(); from json file
 
I couldn't load the lblGanhadores.Text = sorteio.numeroDeGanhadores.ToString(); from json file

Perhaps because numeroDeGanhadores is one of the leaves of your data structure, but in your code you are treating like a child of the root of the object:
1691728872926.png
 

Latest posts

Back
Top Bottom