|
Sorry.
Could not be too urgent to clean up the rest.
Once again I apologize.
|
|
|
|
|
Here you go:
public class SlimList<T> : IList<T>
{
#region Constants
private const int OVERHEAD = 31;
private const int MAX_CAPACITY = 1 << 30;
private const string NEGATIVE_CAPACITY = "Capacity cannot be less than 0.";
#endregion
#region Variables
private T[][] items;
private int count;
private int capacity;
private int capacityIndex;
private int lastSize;
#endregion
#region Properties
public T this[int index]
{
get
{
ValidateIndex(index);
int firstIndex = (index == 0 ? 0 : (int)Math.Truncate(Math.Log(index, 2)));
int baseIndex = (firstIndex == 0 ? 0 : (1 << firstIndex));
int offset = index - baseIndex;
return items[firstIndex][offset];
}
set
{
ValidateIndex(index);
int firstIndex = (index == 0 ? 0 : (int)Math.Truncate(Math.Log(index, 2)));
int baseIndex = (firstIndex == 0 ? 0 : (1 << firstIndex));
int offset = index - baseIndex;
items[firstIndex][offset] = value;
}
}
public int Count
{
get
{
return this.count;
}
}
public int Capacity
{
get
{
return this.capacity;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
#endregion
#region Constructors
public SlimList()
{
this.Clear();
}
public SlimList(int initialCapacity)
{
this.Clear();
if (initialCapacity == 0)
{
return;
}
else if (initialCapacity < 0)
{
throw new InvalidOperationException(NEGATIVE_CAPACITY);
}
this.items[0] = new T[2];
this.capacity = 2;
this.capacityIndex = 0;
this.lastSize = 1;
while (this.capacity < initialCapacity)
{
this.capacityIndex++;
this.lastSize <<= 1;
this.capacity <<= 1;
this.items[this.capacityIndex] = new T[this.lastSize];
}
}
public SlimList(IEnumerable<T> collection)
{
this.Clear();
foreach (T item in collection)
{
this.Add(item);
}
}
#endregion
#region Methods
public int IndexOf(T item)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < count; i++)
{
if(comparer.Equals(item, this[i]))
{
return i;
}
}
return -1;
}
private void ValidateIndex(int index)
{
if (index < 0 || index >= count)
{
throw new IndexOutOfRangeException();
}
}
public void Insert(int index, T item)
{
this.ValidateIndex(index);
this.Add(this[this.count - 1]);
for (int i = this.count - 1; i > index; i--)
{
this[i] = this[i - 1];
}
this[index] = item;
}
public void RemoveAt(int index)
{
this.ValidateIndex(index);
for (int i = index; i + 1 < this.count; i++)
{
this[i] = this[i + 1];
}
this.count--;
}
public void Add(T item)
{
count++;
if (count > capacity)
{
if (capacity == 0)
{
capacity = 1;
this.lastSize = 1;
}
else if (capacity == 2)
{
this.lastSize = 1;
}
else if (capacity == MAX_CAPACITY)
{
throw new InvalidOperationException("The list is full.");
}
capacity <<= 1;
this.capacityIndex++;
this.lastSize <<= 1;
this.items[this.capacityIndex] = new T[this.lastSize];
}
this[count - 1] = item;
}
public void Clear()
{
items = new T[OVERHEAD][];
this.count = 0;
this.capacity = 0;
this.capacityIndex = -1;
this.lastSize = 0;
}
public bool Contains(T item)
{
return this.IndexOf(item) >= 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
for (int i = 0; i < this.count; i++)
{
array[i + arrayIndex] = this[i];
}
}
public bool Remove(T item)
{
int index = this.IndexOf(item);
bool removed;
if (index >= 0)
{
this.RemoveAt(index);
removed = true;
}
else
{
removed = false;
}
return removed;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < this.count; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
Actually, none of that has anything to do with multidimensional lists. See, isn't it annoying when somebody posts a bunch of code that is completely unrelated to the topic at hand? Also, see how nice my code looks (with all the colors and tabs)? You can do that by surrounding your code with a PRE tag and specifying the lang attribute (in your case, it would be C#). For example, you could type this:
<pre lang="C#">int x = 5;</pre>
|
|
|
|
|
I haven't read all of that, but I was shocked by this bit inside your constructor:
aspdotnetdev wrote: while (this.capacity < initialCapacity)
{
this.capacityIndex++;
this.lastSize <<= 1;
this.capacity <<= 1;
this.items[this.capacityIndex] = new T[this.lastSize];
}
Why on earth would you create several arrays when you only need one?
If you don't know how to get the next power of 2 directly, then loop over the capacity WITHOUT creating the beast, and create one array once you decided on the right size.
Finding the next power of 2 is similar to locating the most significant bit set (x86 has an instruction that does that, so a little P/Invoke to assembly code could be the fastest), or determining the integer log2 (I am NOT suggesting you use the Math class for this!).
Without special tricks, the fastest way AFAIK is a binary search with some nested IFs that mask certain bit fields.(Is any bit set in the top half? is any bit set in the top quarter? etc)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
Haha, very observant. I discuss that at the bottom of my article, SlimList. The instruction you are talking about is BSR (bit scan reverse). It checks for the number of consecutive zeros in the most significant bits, or something like that. Point is, it gets you a fast way to calculate the base-2 integer log. I didn't want SlimList to be platform-dependent, so I didn't go with BSR. Also, I didn't want the code to be confusing, so I didn't go with a binary search of the bits... rather, I went with Math.Log, because it was the most obvious.
Luc Pattyn wrote: Why on earth would you create several arrays when you only need one?
To avoid having to reallocate an array twice the size of the original array and copy values over when the number of elements has exceeded the capacity of the original array (the common technique for creating a List structure). Doing so has the potential to slow things down due to excessive memory allocations and also has the down-side of having 3x the required memory (1x by the old array and 2x by the new array). With SlimList, the old arrays take up 1x memory and the new array takes up 1x memory, for a total of 2x memory during list expansion. And thanks to my use of Log to directly calculate the proper index, the indexing performance is still O(1) (though it could be argued that Log is not truly an O(1) operation, it could be implemented as such with an array to perform the lookup rather than perform the calculation, or in hardware, as the BSR instruction demonstrates, though both are moot points when you consider that you would have to use an n-bit number to perform the lookup anyway with either List or SlimList). Keep in mind that my article is mostly academic in nature. I created it to present a new data structure, not to provide a class that should be used out of the box (as it is implemented, it has some performance issues, which are discussed at the bottom of the article). If your code will only be used on x86 computers, perhaps you go with BSR. Or maybe you go with a different instruction on a different platform. But most of the time, the best choice is to just use .Net's List.
|
|
|
|
|
aspdotnetdev wrote: (though it could be argued that Log is not truly an O(1) operation, it could be implemented as such with an array to perform the lookup rather than perform the calculation, or in hardware, as the BSR instruction demonstrates, though both are moot points when you consider that you would have to use an n-bit number to perform the lookup anyway with either List or SlimList)
Sorry in advance for that "little" digression
|
|
|
|
|
aspdotnetdev wrote: as it is implemented, it has some performance issues, which are discussed at the bottom of the article in the forum
FTFM.
|
|
|
|
|
great little monologue.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
I have a requirement to be able to send keypresses to another application(yes this is the only option). I also cannot bring that application to the foreground(voiding the use of sendkeys). Ive found "postmessage" which does work, except that it seems to send the key directly to the program instead of simulating a keyboard press. So I need something that makes the application think it has come directly from the keyboard(which will also mean that another logging application I have will be able to pick the press up - as it doesnt with postmessage).
Is there maybe a function that I can call with p/invoke?
Thanks
Strive to be humble enough to take advice, and confident enough to do something about it.
|
|
|
|
|
roguemat wrote: I also cannot bring that application to the foreground(voiding the use of sendkeys).
Not sure if this is any help, but: Have you thought about bringing it to the foreground outside of the visible desktop area?
You could bring the window up at -1000, -1000 (and make sure it's window size doesn't exceed that of course), use SendKey and put it back to its original position. May not be very elegant, but it should work.
Standards are great! Everybody should have one!
|
|
|
|
|
I am tryng to split a process in some methods stopping the methods with objects ManualResetEvent and AutoResetEvent but I am having problems with the WaitHandle.WaitAll() method with this method I want stop the proccess until everyone event is pointed, but I receive the error message of "Not valid WaitAll for various events in a STA proccess"
Please ho can I solve the problem
|
|
|
|
|
Use Google. The first hit that comes up already provides a solution:
private void WaitAll(WaitHandle[] waitHandles) {
if (Thread.CurrentThread.ApartmentState == ApartmentState.STA) {
foreach(WaitHandle myWaitHandle in waitHandles) {
WaitHandle.WaitAny(new WaitHandle[]{myWaitHandle});
}
}
else {
WaitHandle.WaitAll(waitHandles);
}
}
Standards are great! Everybody should have one!
|
|
|
|
|
You can start a new thread, set its apartment state to MTA and call the WaitAll method there. Then just call Join on the thread. It is much better then using a foreach loop.
|
|
|
|
|
Hi anyone, i asking about managed and unmanaged code and why we need that???
I need a good reference to know in depth about them...........
Regards
|
|
|
|
|
This looks ok. Or you can just try Wikipedia and the references in the bottom of the page.
Standards are great! Everybody should have one!
|
|
|
|
|
I would also recommend you pick up a book like CLR via C# and read.
Now...bring me that horizon. And really bad eggs...Drink up me hearties, YO HO!
|
|
|
|
|
|
I have an address book program completely done, except for one thing...
When a name is highlighted in the listbox, I need all of their information displayed in the related textboxes. All the contact information is stored in an array. I was playing with the code, and I know how to display just the information in the listbox, which is the first and last name, but I need ALL of the contact info displayed in the textboxes. I have included my code, and a screenshot of what should happen when a name is selected from the listbox.
Screen Shot[]
public partial class frmAddressBook : Form
{
string[] Contacts = new string[20];
int i = 0;
public frmAddressBook()
{
InitializeComponent();
}
private void AddressBook_Load(object sender, EventArgs e)
{
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnAdd_Click(object sender, EventArgs e)
{
string lastName = tbxLastName.Text;
string firstName = tbxFirstName.Text;
string street = tbxStreet.Text;
string city = tbxCity.Text;
string state = tbxState.Text;
string zip = tbxZip.Text;
if (i < 20)
{
Contacts[i] = lastName + ", " + firstName;
i++;
}
else
{
MessageBox.Show("The Address Book Can Hold a Maximum of 20 Contacts.", "Address Book Full");
}
tbxFirstName.Text = "";
tbxLastName.Text = "";
tbxStreet.Text = "";
tbxCity.Text = "";
tbxState.Text = "";
tbxZip.Text = "";
lstContacts.Items.Clear();
for (int j = 0; j < 20; j++)
{
if (Contacts[j] != null)
{
lstContacts.Items.Add(Contacts[j].ToString().Trim());
}
}
}
private void btnDelete_Click(object sender, EventArgs e)
{
for (int k = 0; k < Contacts.Length; k++)
{
try
{
if (Contacts[k].Contains(lstContacts.SelectedItem.ToString()))
{
Contacts[k] = null;
}
}
catch
{
}
}
lstContacts.Items.Clear();
for (int j = 0; j < 10; j++)
{
if (Contacts[j] != null)
{
lstContacts.Items.Add(Contacts[j].ToString().Trim());
}
}
}
private void lstContacts_SelectedIndexChanged(object sender, EventArgs e)
{
tbxFirstName.Text = lstContacts.SelectedItem.ToString();
}
}
}
|
|
|
|
|
Hi,
I have a lot of comments, here are some:
1.
you should not try and keep a lot of information in a single string, so string[] Contacts isn't a good choice.
2.
you should also not try and keep an unknown number of items in an array, as that will become a functional limitation, and needs code to guard you against an overflow. Instead use some kind of list; ArrayList is simple, however it got superceded by List<sometype> which is known as a generic list.
3.
a ListBox can hold items of any kind you choose, not just strings. So what you could and should do is:
- declare a Contact class, with all the fields you like;
- create, then add, such Contact instances to the ListBox;
- to get it painted, do one of these:
a) give Contact a ToString() method that lists all fields, each with a constant width (i.e. use string.PadRight() or string.PadLeft() to add spaces;
b) make the ListBox ownerdrawn, and provide a DrawItem handler which basically does a Graphics.DrawString() for each of the fields.
4.
If you want to be able to sort your contacts on each of the fields, then you would be better of with a DataGridView
5.
some comments on coding style:
- don't call ToString() on strings, as it doesn't achieve anything (see Contacts[j].ToString())
- don't use short identifiers for class members (your int i); a one-letter identifier is OK for a local for loop, not for a state variable.
- don't create empty catch blocks; always specify what it is you catch, and then show it, so no problem can go unnoticed and waste hours of debugging. Example:
try {
...
} catch(Exception exc) {
MessageBox.Show(exc.ToString());
}
6.
and finally, if you haven't done so yet, buy and study a book on C#, it introduces you to all major language features and good coding practices.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
I will take some of your suggestions into consideration. I am doing all of this as the guidelines in my C# book dictate. I am trying to learn C#, I just need some help every now and then on some of the problems in the book. Thi sis the first real problem I have come across, and I am totally lost.
|
|
|
|
|
CarlMartin10 wrote: I just need some help every now and then
No problem. You found the right forum to ask away. Just make sure you show you made an effort, as you did, and people will be glad to help.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that. [The QA section does it automatically now, I hope we soon get it on regular forums as well]
|
|
|
|
|
Instead of storing your contact data as an array of strings. You could create another class to contain all the data you need, and then use a list or array of that. For example:
class ContactData
{
string FirstName;
string LastName;
string Address;
string City;
string State;
string Zip;
public override string ToString()
{
return FirstName + ", " + LastName;
}
}
You could then add this class to your listbox just as you do with your current array of strings.
The override for ToString is so that the listbox knows what text to display for that item. So you can just do this when adding items (assuming Contacts is now an array of ContactData )
for (int j = 0; j < 20; j++)
{
if (Contacts[j] != null)
{
lstContacts.Items.Add(Contacts[j]);
}
}
Then, to get the information back out you can get the selected item from your listbox and cast it back to a ContactData and access your information:
private void lstContacts_SelectedIndexChanged(object sender, EventArgs e)
{
ContactData myData = lstContacts.SelectedItem as ContactData;
tbxFirstName.Text = myData.FirstName;
...
}
My current favourite word is: Sammidge!
-SK Genius
Game Programming articles start - here[ ^]-
|
|
|
|
|
I would love to do it this way, but that defeats the purpose of the problem, which is to illustrate how to do it with an array. I need to learn C#, and this book has been very useful, but it really does not explain how to do this part, at all.
|
|
|
|
|
let us consider we have two forms form1 and form2 and there are some information in form1 that i would like to use in form2... which method should i use to perform this action?
|
|
|
|
|
if form1 create form2 then from form2 you can define a public var. like this:
int x;
public int X
{
set
{
x=value;
}
}
then when you create you can send the var. like this:
form2 f2=new form2();
f2.X=5;
f2.show();
|
|
|
|
|
suppose we have a tab of buttons in form1 and i want to use the text of the clicked button in form2... how can i do such a thing?
|
|
|
|
|
use delegation:
in form1 create textbox and put:
public delegate void dd(string s);
public static dd d;
and put (d=new dd(write);) in public Form1()
then write method (write):
privet void write(string s)
{
textbox1.text=s;
}
in form2 create button and textbox then in click event put:
Form1.d(textbox1);
modified on Wednesday, January 20, 2010 6:53 PM
|
|
|
|
|