Go Back   RunUO - Ultima Online Emulation > Developer's Corner > Programming > C#

C# C# Discussion

Reply
 
Thread Tools Display Modes
Old 12-28-2006, 12:11 AM   #1 (permalink)
Forum Expert
 
BeneathTheStars's Avatar
 
Join Date: Jul 2005
Location: (South)Tip o' Texas
Posts: 1,294
Send a message via AIM to BeneathTheStars Send a message via MSN to BeneathTheStars
Default 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)
BeneathTheStars is offline   Reply With Quote
Old 12-28-2006, 12:41 AM   #2 (permalink)
Forum Expert
 
Join Date: Feb 2005
Age: 24
Posts: 985
Send a message via AIM to Nochte
Default

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)
Nochte is offline   Reply With Quote
Old 12-28-2006, 12:56 AM   #3 (permalink)
Forum Expert
 
mordero's Avatar
 
Join Date: Nov 2003
Location: Illinois, USA
Age: 21
Posts: 2,911
Default

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...
mordero is offline   Reply With Quote
Old 12-28-2006, 01:12 AM   #4 (permalink)
Forum Expert
 
BeneathTheStars's Avatar
 
Join Date: Jul 2005
Location: (South)Tip o' Texas
Posts: 1,294
Send a message via AIM to BeneathTheStars Send a message via MSN to BeneathTheStars
Default

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)
BeneathTheStars is offline   Reply With Quote
Old 12-28-2006, 01:26 AM   #5 (permalink)
ConnectUO Creator
 
Jeff's Avatar
 
Join Date: Jan 2004
Location: In your mom
Age: 27
Posts: 4,760
Default

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

Dictionary<Type, int>
__________________
Jeff Boulanger
ConnectUO - Core Developer

Want to help make ConnectUO better? Click here to submit your ideas/requests
Use your talent to compete against other community members in RunUO hosted coding competitions

If you know XNA (even if its just a little) or are a good artist(2d or 3d) and are interested in making games for a hobby send me a pm or drop by #xna in irc.runuo.com. I'm looking to put together a small game development team.


Please do not pm me for support. If you are having issues please post in the appropriate forum. Thanks for your continued support of both ConnectUO and RunUO
Jeff is offline   Reply With Quote
Old 12-28-2006, 01:46 AM   #6 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Quote:
Originally Posted by Jeff
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] );
	}
}

Last edited by Sep102; 12-28-2006 at 02:04 AM.
Sep102 is offline   Reply With Quote
Old 12-28-2006, 02:06 AM   #7 (permalink)
Forum Expert
 
mordero's Avatar
 
Join Date: Nov 2003
Location: Illinois, USA
Age: 21
Posts: 2,911
Default

Quote:
Originally Posted by BeneathTheStars View Post
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.
mordero is offline   Reply With Quote
Old 12-28-2006, 02:19 AM   #8 (permalink)
Forum Expert
 
BeneathTheStars's Avatar
 
Join Date: Jul 2005
Location: (South)Tip o' Texas
Posts: 1,294
Send a message via AIM to BeneathTheStars Send a message via MSN to BeneathTheStars
Default

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];
	}

	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 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..

Last edited by BeneathTheStars; 12-28-2006 at 02:21 AM.
BeneathTheStars is offline   Reply With Quote
Old 12-28-2006, 02:22 AM   #9 (permalink)
Forum Expert
 
BeneathTheStars's Avatar
 
Join Date: Jul 2005
Location: (South)Tip o' Texas
Posts: 1,294
Send a message via AIM to BeneathTheStars Send a message via MSN to BeneathTheStars
Default

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]);
            }
        }
    }
}
BeneathTheStars is offline   Reply With Quote
Old 12-28-2006, 02:28 AM   #10 (permalink)
Forum Expert
 
mordero's Avatar
 
Join Date: Nov 2003
Location: Illinois, USA
Age: 21
Posts: 2,911
Default

Quote:
Originally Posted by BeneathTheStars View Post
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.
mordero is offline   Reply With Quote
Old 12-28-2006, 03:07 AM   #11 (permalink)
Forum Expert
 
BeneathTheStars's Avatar
 
Join Date: Jul 2005
Location: (South)Tip o' Texas
Posts: 1,294
Send a message via AIM to BeneathTheStars Send a message via MSN to BeneathTheStars
Default

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!
BeneathTheStars is offline   Reply With Quote
Old 12-28-2006, 03:10 AM   #12 (permalink)
Forum Expert
 
mordero's Avatar
 
Join Date: Nov 2003
Location: Illinois, USA
Age: 21
Posts: 2,911
Default

Glad to help
mordero is offline   Reply With Quote
Old 12-28-2006, 03:18 AM   #13 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Quote:
Originally Posted by BeneathTheStars
-------------------------------------
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 is offline   Reply With Quote
Old 12-28-2006, 03:20 AM   #14 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Quote:
Originally Posted by BeneathTheStars View Post
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.

Last edited by Sep102; 12-28-2006 at 03:24 AM.
Sep102 is offline   Reply With Quote
Old 12-28-2006, 11:49 AM   #15 (permalink)
Forum Expert
 
Join Date: Feb 2005
Age: 24
Posts: 985
Send a message via AIM to Nochte
Default

Are you confined to the C# language? If not, PM me (mainly 'cause this thread should stay on-topic)
Nochte is offline   Reply With Quote
Reply

Bookmarks


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off



Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0 RC5