RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Repeats in Arrays

Repeats in Arrays

I have a problem with an array, and it seems like an easy solution that i have seen before..but cannot find where...

I have a array filled with...animals, lots of different types. I want the array to count how many of each animal there are in the array(done that)..without counting the same animal again later on...


Code:
private void CountTypes()
        {
            foreach (string s in m_types)
            {
                int count = 0;
                for (int i = 0; i < m_types.Count; i++)
                {
                    if (s == m_types[i].ToString())
                    {
                        if (count == 0)
                            m_filetypes.Add(m_types[i].ToString());
                        count++;
                    }
                }
                m_filecount.Add(count);
                
            }
            for (int i = 0; i < m_filetypes.Count; i++)
            {
                SetText4(""+m_filetypes[i]+" "+m_filecount[i]);
            }
        }

It should find a 'animal', count how many there are, and move on. Then disregard it the next time it runs into it.

I cannot remove the 'animal' for it would change the size of the array, and replacing the animal did nothing...


('animals' are an example)
 

Nochte

Wanderer
create a hash (or hash style array).
use the animal type as the index.
loop through the original array. foreach animaltype in the array, increment the integer at the animaltype's index. you only have to go through the array one time this way.
i use the same technique to calculate an image's precise histogram, and it works super quick.
(you'll have to pardon me on this one, i'm a ruby programmer much more than c#, so i'm not sure exactly what datatype you'd use)
 

mordero

Knight
Ok, I think this is what you want, but Im not sure
Code:
 public static Dictionary<string,int> CountTypes(string[] array)
        {
            Dictionary<string, int> types = new Dictionary<string, int>();
            foreach (string s in array)
            {
                if (!types.ContainsKey(s))
                {
                    types.Add(s, 1);
                }
                else
                {
                    types[s] += 1;
                }
            }
            return types;
        }


This was my example to test it

Code:
static void Main(string[] args)
        {
            string[] m_types = new string[] { "Dog", "Cat", "Donkey", "Dog", "Lizard","Cat","Zebra", "Horse", "Horse","Dog" };

            Dictionary<string, int> types = CountTypes(m_types);
            foreach (string s in types.Keys)
            {
                Console.WriteLine("{0} - {1}",s,types[s]);
            }

            Console.WriteLine();
            Console.WriteLine("Total types - {0}",types.Count);     
            Console.ReadLine();

        }

I think that should help out, hopefully...
 
Thats what i thought would happen.. the main problem behind this is that i do not know what strings are going to be put into these array lists. The top part of the code(which i diddnt provide, i will later) goes and looks for that info. So, something like dictionaries would not be possible.
But, thanks for that sample..:)

@Nochte: sounds interesting, ill check it out!
(wont let me + ya, Nochte)
 

Jeff

Lord
if they are animals, and these animals are different objects, cant u do

Dictionary<Type, int>
 

Sep102

Page
Jeff said:
if they are animals, and these animals are different objects, cant u do

Dictionary<Type, int>

That would be a possibility, but looking at the example code that's provided, animals are only String's, not Type's (as long as that code is representative of the data set).


There are basically two ways to do this, record the animals that have been processed already (which can be done with a hash table, as has been demonstrated already), or sort the array of animals first, then only do the actual processing each time the animal changes and keep a local count of the current animal like you do now. Of course each has its own benefits and drawbacks.

Also, you don't need to know which animals there are in the array beforehand to use a Dictionary, mordero just used one in his example, likely to make it simpler than it would have been had he not. Rather than calling Add the first time you encounter it, you could just use the index operator that the Dictionary has that adds the key with a given value if it is not in the table and sets the key's value to a given value if it already exists. Then you could just check to see if the value is equal to one and if so do the processing on it since it's the first time the animal has been encountered.

Of course, this is essentially what Nochte was advocating as well, I was just more long winded about it.


Since I'm bored, a more concrete example could be
Code:
private void CountTypes ()
{
	Dictionary<String, Int32> animals = new Dictionary<String, Int32>();
		
	foreach ( string s in m_types )
	{
		++animals[s];
	}

	foreach ( KeyValuePair<String, Int32> keyVal in animals )
	{
		m_filetypes.Add( keyVal.Key );
		m_filecount.Add( keyVal.Value );
	}

	for ( int i = 0; i < m_filetypes.Count; i++ )
	{
		SetText4( "" + m_filetypes[i] + " " + m_filecount[i] );
	}
}
 

mordero

Knight
BeneathTheStars;625951 said:
Thats what i thought would happen.. the main problem behind this is that i do not know what strings are going to be put into these array lists. The top part of the code(which i diddnt provide, i will later) goes and looks for that info. So, something like dictionaries would not be possible.
But, thanks for that sample..:)

You dont need to know the strings in my example as long as you have them in an array. It will go through and count them for you and just store them in the dictionary so the key is the string and the value is the number of times it was found in the array.

If you wanted it outputted in the same format as your example of
Code:
SetText4(""+m_filetypes[i]+" "+m_filecount[i]);

it would just be

Code:
Dictionary<string, int> blah = CountTypes(m_types);
            foreach (string filetype in blah.Keys)
            {
                SetText4(filetype + " " + blah[filetype]);//you dont need that first ""+
            }

now if instead of using strings, you are using actual different types, then Im pretty sure you would only need to change a couple of things in my method.
 
Ok see a lot of new code..so if you all dont mind..im going to ask a few question on what these snippets do?

Code:
 public static Dictionary<string,int> CountTypes(string[] array)
        {
            Dictionary<string, int> types = new Dictionary<string, int>();
            foreach (string s in array)
            {
                if (!types.ContainsKey(s))
                {
                   types.Add(s, 1);
                }
                else
                {
                   types[s] += 1;
                }
            }
            return types;
        }
So this is going to go through each string in the array, find if it has been stored in a separate array, if not- add it, if it sees it again.. increase its value ?

-------------------------------------
Code:
private void CountTypes ()
{
	Dictionary<String, Int32> animals = new Dictionary<String, Int32>();
		
	foreach ( string s in m_types )
	{
		++animals[s];
	}

	[COLOR="Red"]foreach ( KeyValuePair<String, Int32> keyVal in animals )
	{
		m_filetypes.Add( keyVal.Key );
		m_filecount.Add( keyVal.Value );
	}[/COLOR]

	for ( int i = 0; i < m_filetypes.Count; i++ )
	{
		SetText4( "" + m_filetypes[i] + " " + m_filecount[i] );
	}
}
Go through and add each string to a dictionary..im lost on what the function of the red area is.. :)

-------------------

The program i am making goes through a destination on your hard drive, and will 'take inventory' of all the file types in that destination..it will say "144 files - 44 were .ppt 100 were .isd " - like that..
 
The code:

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Threading;
using System.Security;
using System.Diagnostics;

namespace DiskAnalyzer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public int counter = 0;
        public string location,location2 = "";
        public bool active = false;
        private ArrayList m_types = new ArrayList();
        private ArrayList m_filetypes = new ArrayList();
        private ArrayList m_filecount = new ArrayList();
        delegate void SetTextCallback(string text);
        delegate void SetActiveCallback(bool on);
        private void button1_Click(object sender, EventArgs e)
        {
            Status(counter, location, active);
            Thread th = new Thread(new ThreadStart(startproc));
            th.Start();
        }

        private void Status(int counter, string location, bool active)
        {
            SetText(location);
            SetText2(counter.ToString());
            SetText3(active.ToString());
        }
        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true. -msdn
            if (this.label5.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.label5.Text = text;
            }
        }
        private void SetText2(string text)
        {
            if (this.label6.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText2);
                this.Invoke(d, new object[] { text });
            }
            else
                label6.Text = text;
        }
        private void SetText3(string text)
        {
            if (this.label7.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText3);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.label7.Text = text;
            }
        }
        private void SetText4(string text)
        {
            if (this.textBox1.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText4);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text += text;
            }
        }
        private void SetOn(bool enable)
        {
            if (this.button1.InvokeRequired)
            {
                SetActiveCallback d = new SetActiveCallback(SetOn);
                this.Invoke(d, new object[] { enable });
            }
            else
            {
                this.button1.Enabled = enable;
            }
        }
        public void startproc()
        {
            location2 = textBox2.Text;
            DirectoryInfo di = new DirectoryInfo(@location2);
            active = true;
            SetOn(false);
            Status(counter, location,active);
            CountFiles(di);
            CountTypes();
            Reset();
        }
        private void Reset()
        {
            active = false;
            Status(counter, location, active);
            counter = 0;
            MessageBox.Show("Done!");
            SetOn(true);
        }
        private void CountFiles(DirectoryInfo dri)
        {
            try {
                FileInfo[] gfiles = dri.GetFiles();
                foreach (FileInfo fl in gfiles)
                {
                    
                    counter += 1;
                    m_types.Add(fl.Extension.ToString().ToLower());
                }
                DirectoryInfo[] dri2 = dri.GetDirectories();
                foreach (DirectoryInfo drx in dri2)
                    CountFiles(drx);
            }
            catch { }
            location = dri.FullName.ToString();
            Status(counter, location, active);
        }
        private void CountTypes()
        {
            foreach (string s in m_types)
            {
                int count = 0;
                for (int i = 0; i < m_types.Count; i++)
                {
                    if (s == m_types[i].ToString())
                    {
                        if (count == 0)
                            m_filetypes.Add(m_types[i].ToString());
                        count++;
                    }
                }
                m_filecount.Add(count);
                
            }
            for (int i = 0; i < m_filetypes.Count; i++)
            {
                SetText4(""+m_filetypes[i]+" "+m_filecount[i]);
            }
        }
    }
}
 

mordero

Knight
BeneathTheStars;625966 said:
Ok see a lot of new code..so if you all dont mind..im going to ask a few question on what these snippets do?

Code:
 public static Dictionary<string,int> CountTypes(string[] array)
        {
            Dictionary<string, int> types = new Dictionary<string, int>();
            foreach (string s in array)
            {
                if (!types.ContainsKey(s))
                {
                   types.Add(s, 1);
                }
                else
                {
                   types[s] += 1;
                }
            }
            return types;
        }
So this is going to go through each string in the array, find if it has been stored in a separate array, if not- add it, if it sees it again.. increase its value ?

Yep, it will go through an array of strings that you put into it. If it finds a string that it hasnt found before, it will create a new key/value pair for it setting the value to 1. If it has found that string before, it will just add 1 to the value. So the value for each key is just the number of times it found the string in the original array.
 
Got it to do as i want.. thanks very much mordero, Sep102, Jeff, and Nochte!

Here it is:
Code:
private void CountTypes()
        {
            Dictionary<string, int> types = new Dictionary<string, int>();
            foreach (string s in m_types)
            {
                if (!types.ContainsKey(s))
                    types.Add(s, 1);

                else
                    types[s] += 1;
            }
            foreach (string filetype in types.Keys)
            {
                if (types[filetype] == 1)
                    continue;
                
                SetText4(filetype + " " + types[filetype] + "\r\n");
            }
        }


Once i get the whole thing done, i will post it!
 

Sep102

Page
BeneathTheStars said:
-------------------------------------
Code:

Code:
private void CountTypes ()
{
	Dictionary<String, Int32> animals = new Dictionary<String, Int32>();
		
	foreach ( string s in m_types )
	{
		++animals[s];
	}

	foreach ( KeyValuePair<String, Int32> keyVal in animals )
	{
		m_filetypes.Add( keyVal.Key );
		m_filecount.Add( keyVal.Value );
	}

	for ( int i = 0; i < m_filetypes.Count; i++ )
	{
		SetText4( "" + m_filetypes[i] + " " + m_filecount[i] );
	}
}

Go through and add each string to a dictionary..im lost on what the function of the red area is..

The function of the code as a whole is to first loop through each of the types, counting the amount of times each time is encountered, then going through each unique type in "animals" and adding it to the m_filetypes array and the number of times it was encountered to the m_filecount array. Then using your original loop to set the text using those arrays.
 

Sep102

Page
BeneathTheStars;625977 said:
Got it to do as i want.. thanks very much mordero, Sep102, Jeff, and Nochte!

Here it is:
Code:
private void CountTypes()
        {
            Dictionary<string, int> types = new Dictionary<string, int>();
            foreach (string s in m_types)
            {
                if (!types.ContainsKey(s))
                    types.Add(s, 1);

                else
                    types[s] += 1;
            }
            foreach (string filetype in types.Keys)
            {
                if (types[filetype] == 1)
                    continue;
                
                SetText4(filetype + " " + types[filetype] + "\r\n");
            }
        }


Once i get the whole thing done, i will post it!
So, from what I understand from this method, you want to go through all of the types, find each unique type and count how many times it appeared in the original array, then call SetText4 for any type that appeared more than once in the original array (at least, that's what the if(types[filetype] == 1) check will do, make it skip any types that appeared only once). You would need to get rid of that if you wanted to do what the original code was supposed to have been doing, calling SetText4 for every type.
 
Top