I'm sorting the lines of a text box in reverse alphabetical order, and the code I have works fine:
string[] temp = textBox.Lines;
Array.Sort(temp);
Array.Reverse(temp);
textBox.Lines = temp;
But I'm confused as to why Visual Studio wouldn't let me do:
Array.Sort(textBox.Lines);
Array.Reverse(textBox.Lines);
Mostly I'm trying to figure out the subtleties of C# since I'm still new to it.
EDIT: The second snippet doesn't error out, but it doesn't execute any code (i.e. doesn't appear to do anything).
Here's a few lines of the getter for TextBox.Lines:
public string[] Lines
{
get
{
string text = Text;
ArrayList list = new ArrayList();
...
...
return(string[]) list.ToArray(typeof(string));
}
You're getting a new collection, which has a copy of the data in it from the TextBox. You're not actually sorting the data in the TextBox.
When void Array.Sort is done sorting the array passed back from that property, the original TextBox remains unchanged.
Indeed, your array will be sorted and reversed, but what happens is that will not be assigned to TextBox. Modifying the Lines array has no effect since it is computed property.
You need to assign it to Lines property to see the effect.
Here is the reference to source
This is because textBox.Lines is not exposed as a member variable on the class but rather as a property. Behind the scenes, a property is really two methods, e.g. get_Lines and set_Lines. All you know about the array you get back from get_Lines is that it's an array of strings. There's no guarantee that that property is backed by an actual array--maybe TextBox keeps the text internally as one big string that it then breaks into pieces for you when you call get_Lines. So you're not necessarily modifying the internal list when you call Sort() and Reverse() on the result of get_Lines.
Related
I want to read from and write to individual elements of a VectorOfFloat. The problem is that there's no setter defined, which makes the brackets + index way of accessing the elements read only.
VectorOfFloat vector = new VectorOfFloat(5);
// vector[2] = 2.5F; // does not work
There's a workaround:
convert to array with ToArray()
modify array as desired
write array back with Clear() and Push()
float[] array = vector.ToArray();
array[2] = 2.5F;
vector.Clear();
vector.Push(array); // does work but is retarded
Console.WriteLine(vector[2]);
This seems to be very cumbersome just to write one element Is there a more direct approach to this?
Also, what is the missing setter worth if I can work around it?
The comments are correct. The way to gain access to the unmanaged array is trough the StartAddress property returning an IntPtr.
lock(vector)
{
var ptr_array=(float*)vector.StartAddress.ToPointer();
ptr_array[4]=1.0f;
}
i am using array control in which i am saving value one by one.
now i have to delet one of the element and refresh it simultaneuosly.
for example....
string[] arr= new string(25);
arr[0]="A";
arr[1]="B";
arr[2]="C"; and so on....
now after deleting second element via arr[1]=null;
i want refreshed array like mentioned below...
arr[0]="A";
arr[1]="C"; and so on....
please help...
thanks in advance,,,
It sounds like you should be using a List<string> rather than an array, this would give exactly the functionality you are describing.
Although arrays can be resized (thanks #Austin Brunkhorst), this is not "cheap" and you would you would need to move everything around yourself.
It should be noted, that with lots of inserts and removes Lists can get very inefficient, so you'd be better off with a LinkedList<string>. These have advantages and disadvantages. Google linked list for more info.
When you have a static data amount you should use Array, BUT when you have dinamic data amount you should use List<>.
If you want to resize arrays, you have to create a new and copy all elements from the old to the new one.
arr = arr.Where(s => s != null).ToArray();
If you would use a List<string> you could use methods like List.Remove or List.RemoveAt.
If you'll be adding/deleting entries at arbitrary positions in your collection a lot, you'd be better off using a LinkedList<string> instead
Instead of Array you can go with List
List<int> list = new List<int>();
list.Add(2);
list.Add(3);
list.Add(5);
list.Add(7);
you will get more options like
Contains
Exists
IndexOf
For Removing the items you will get the functions like
Remove
ex: dogs.Remove("bulldog"); // Remove bulldog
RemoveAt
ex: list.RemoveAt(1);
RemoveAll
I'm trying to embed a very basic AI in a game of Tic Tac Toe and I'm running into a problem with the arrays that I use to discern the most suitable square to claim.
I have one array that represents the game grid in its current state and another that represents the way it would look if a certain square were claimed.
The AI kept making weird decisions, so I decided to have it report various information at certain milestones.
string[,] currentGrid;
string[,] hypotheticalGrid;
MessageBox.Show(currentGrid);
hypotheticalGrid = currentGrid;
hypotheticalGrid[x, y] = "O";
MessageBox.Show(currentGrid);
Bear in mind that the above is a very simplified version of the actual code.
The arrays are assigned values along the line and the message boxes are set to display currentGrid as a sequence of its contained values.
Everything works properly except the code between the message boxes.
The problem is that the two message boxes display different results even though the latter is a copy of the former and no changes to currentGrid are specified in the space between the two.
The two lines in between are copied directly from the source code and should only affect the hypothetical grid. As should be obvious, these lines are supposed to reset the hypothetical grid and then add an "O" to the square in question.
However, the "O" also gets placed in the current grid for some reason.
What am I doing wrong?
The line hypotheticalGrid = currentGrid; does not make a copy of currentGrid, instead both variables point to the same array. So any change made in hypotheticalGrid will be seen in currentGrid too.
You should have hypotheticalGrid be a copy of currentGrid:
hypotheticalGrid = (string[,])currentGrid.Clone();
In this case, Clone() will work, because strings are immutable in .NET. In other cases, Clone might not be good enough, just something to be aware of.
The problem is that your assignment:
hypotheticalGrid = currentGrid;
is merely a reference assignment, meaning that now they both point to the same array in memory, so any changes to the hypothetical grid will affect the current grid as well.
You'd need a full item copy in order for them to not interfere with each other.
Keep in mind, that arrays are reference types. Your assignment copies the reference but does not create a duplicate of the array. After the assignment both array variables point to the same array!
You can create an array duplicate like this:
string[] hypotheticalGrid = new string[currentGrid.Length];
Array.Copy(currentGrid, hypotheticalGrid, currentGrid.Length);
Note that this does not create a duplicate of the items contained in the array, but this is not a problem, since strings are immutable. I.e. if you manipulate a string in one of the arrays, this creates a new string and therefore has no effect on the second array.
EDIT:
By looking at the other posts I see that it can be done easier with the Clone method:
string[] hypotheticalGrid = currentGrid.Clone();
I am trying to implement a textbox autocomplete with a custom datasource in the form of an array which shows suggestions on single character input. But when i run the program the autocomplete only starts after the second character input. When i debugged i saw that datas are there in the AutoCompleteNameCollection but it is not showing in the suggestion until the second character input.
This code i have written in the textchange event.
arr = LoadName(empid_txt.Text.Trim()); //arr is string array
namesCollection.AddRange(arr);
this.empid_txt.AutoCompleteMode = AutoCompleteMode.Suggest;
this.empid_txt.AutoCompleteSource = AutoCompleteSource.CustomSource;
this.empid_txt.AutoCompleteCustomSource = namesCollection;
In the LoadEvent I have initialized the AutoCompleteNameCollection with an empty array.
namesCollection.AddRange(arr);// here arr is empty
empid_txt.AutoCompleteMode = AutoCompleteMode.Suggest;
empid_txt.AutoCompleteSource = AutoCompleteSource.CustomSource;
empid_txt.AutoCompleteCustomSource = namesCollection;
But it does't work until the second character input.
However if instead of an array i initialize the AutoCompleteNameCollection with an empty string like : namesCollection.Add(""); it does work for the single character input but some times it gives AccessViolationException: Attempted to read or write protected memory.
So is there any way i can solve this problem?
I can replicate the access violation when setting the AutoCompleteSource in the event handler, it seems like the autocomplete routine may be accessing the AutoCompleteSource while it is being replaced and destroyed.
To prevent this you can put a lock around your code.
lock(this)
{
arr = LoadName(empid_txt.Text.Trim()); //arr is string array
namesCollection.AddRange(arr);
this.empid_txt.AutoCompleteMode = AutoCompleteMode.Suggest;
this.empid_txt.AutoCompleteSource = AutoCompleteSource.CustomSource;
this.empid_txt.AutoCompleteCustomSource = namesCollection;
}
This stopped the access violations.
On load you may populate the TextBox with a sub-set of your data (that can be even cached for future/shared use). If you have a "most common" counter you can use it. As limit condition you may even add a dummy item (if what you get with an empty string is an access violation).
Then, on the TextChange event read the data you need from the database.
I have only one question: you do not want to populate the source until the user starts to type? If there's the problem of network traffic then you move a lot of data. If you move a lot of data then your users will have to wait when they start to type something. Is it acceptable? On the other side if they do not wait too much maybe data stream is not so big and you can put that logic in a BackgroundWorker in the constructor of your form (or not far from that time).
AutoComplete suggests after the second char is being pressed is normal because in the first place, you have initialized the arr (which is your custom datasource) into an empty array. You have populated your arr in TextChanged event and that's why AutoComplete works at the second char because your datasource is filtered based on your first char (which is definitely what you don't want).
Here's a suggestion:
On the FormLoad event of your application, fill arr with all the possible suggestions (I think the source of suggestion is from database right?). This will allow textbox to suggest on your first char.
When you have entered the first char, on the TextChanged event reload your arr datasource based on the prevous character being entered.
Hope it helps.
If 'arr' is empty when you initialize the textbox then there is nothing to compare to. You have to initialize AutoCompleteCustomSource to a valid array before you start typing. You are initializing in textchange event, when the user has already typed a character.
You need to populate the namesCollection before the code is changed - in Initialize.
On Form Load call the Textbox autocomplete method.
public void autocompleteData()
{
//SuggestStrings will have the logic to return array of strings either from cache/db
var CurrentuserId = CloudKaseWSClient.GetUserDetail(tokenUsr, tokenPasswd, Username);
List<string> l = new List<string>();
var SearchResults = ("Select Database Query").ToList();
foreach (var i in SearchResults)
{
l.Add(i.name);
}
string[] arr = l.ToArray();
AutoCompleteStringCollection collection = new AutoCompleteStringCollection();
collection.AddRange(arr);
txtSearchUser.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
txtSearchUser.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtSearchUser.AutoCompleteCustomSource = collection;
}
OR You want to set static data for AutoComplete Textbox than you have to set In Design view for Textbox property of AutocompleteMode to set SuggestAppend,AutocompleteSource to set CustomSource and add static value inAutocompleteCustomSource.
I hope this solution helps to you..
Happy Coding.:)
If I have
List<String> text
how can I create a sub-list of all continious elements within a specific range e.g.
List<String> subList = /* all elements within text bar the first 2*/
Also are there any other useful List manipulation tips & tricks that might be useful?
This will work even without LINQ:
List<String> subList = text.GetRange(2, text.Count - 2);
Edit: Fixed a typo.
subList = text.Skip(2).ToList()
Skip(n) returns an IEnumerable<> with all elements except the first n.
When you really need a list after that, ToList() converts it back.
If you're on 3.5, then there are a lot of new and interesting methods available on List. Just check out the section 'Extension methods' here: http://msdn.microsoft.com/en-us/library/d9hw1as6.aspx