Im trying to sort a listbox full of numbers numerically. Why doesnt this work?
{
ArrayList Sorting = new ArrayList();
Sorting.Add (lbNumbers.Text);
int[] items = new int[Sorting.Count];
Sorting.CopyTo(items);
Array.Sort(items);
lbNumbers.Items.Add(items);
}
Probably because when your numbers are represented as strings, they will not sort the way you expect. They will sort as strings and not as numbers.
For example, if you had a list such as:
10
9
101
It would be sorted as:
10
101
9
First, parse the string-elements, then sort.
// the itemList is your lbNumbers.Text
var itemList = new List<string> {"9", "1", "10", "11"};
// use TryParse if you're not sure if really all elements are numbers
var numberList = itemList.Select(int.Parse).ToList();
numberList.Sort();
ArrayList Sorting = new ArrayList();
foreach (var o in listBox1.Items) {
Sorting.Add(o);
}
Sorting.Sort();
listBox1.Items.Clear();
foreach (var o in Sorting) {
listBox1.Items.Add(o);
}
ADDED: For sort in descending order,
1.Create a class ReverseSort as shown below:
// implementation:
public class ReverseSort : IComparer
{
public int Compare(object x, object y)
{
// reverse the arguments
return Comparer.Default.Compare(y, x);
}
}
2.Replace the code line of Sort with this line:
Sorting.Sort(new ReverseSort());
You are sorting lbNumbers.Text => strings
You must clear before sorting
ArrayList arrayList = new ArrayList();
foreach (object o in lbNumbers.Items)
{
arrayList.Add(o);
}
arrayList.Sort();
lbNumbers.Items.Clear();
foreach(object o in arrayList)
{
lbNumbers.Items.Add(o);
}
Using a little bit of LINQ
string list = "1,24,3,10,12,11";
//Split the string into the tokens containing the numbers
string[] tokens = list.Split(',');
//Parse each string representing an integer into an integer
//return the resultant object as an array of integers
int[] sorting = tokens.Select(x => int.Parse(x)).ToArray<int>();
//Sort them numerically and return as an array of integers
sorting = sorting.OrderBy(x => x).ToArray<int>();
//Display them to convince ourselves it works.
foreach (int x in sorting)
{
Console.WriteLine(x);
}
Console.ReadLine();
The parsing and ordering can be done in the same statement, but were split out here for ease of reading.
Try this example:
listBox1.Items.Add(3);
listBox1.Items.Add(1);
listBox1.Items.Add(2);
ArrayList sort = new ArrayList();
foreach (object item in listBox1.Items)
{
sort.Add(item);
}
sort.Sort();
listBox1.Items.Clear();
foreach (int item in sort)
{
listBox1.Items.Add(item);
}
What you where trying to do was to read only the selected text. This way you can get all items in the listbox to an arraylist, sort them and then adding them back again to the listbox.
Keep in mind that all the unsorted items are still there so you need to clear the listbox first. Thats what the listBox1.Items.Clear(); does
Related
I'm trying to make a leaderboard in Windows forms using c# but I can't come up with a solution.
Here is my current code.
lstleaderboard.Items.Add(int.Parse(txtScore.Text));
ArrayList Sorting = new ArrayList();
foreach (var o in lstleaderboard.Items)
{
Sorting.Add(o);
}
Sorting.Sort(new ReverseSort());
lstleaderboard.Items.Clear();
foreach (var o in Sorting)
{
lstleaderboard.Items.Add(o);
}
And I tried altering the code like this:
lstleaderboard.Items.Add(int.Parse(txtScore.Text));
ArrayList Sorting = new ArrayList();
foreach (var o in lstleaderboard.Items)
{
Sorting.Add(o);
}
Sorting.Sort(new ReverseSort());
lstleaderboard.Items.Clear();
foreach (var o in Sorting)
{
lstleaderboard.Items.Add(o + txtName.Text );
}
if (lstleaderboard.Items.Count == 11)
{
lstleaderboard.Items.RemoveAt(lstleaderboard.Items.Count - 1);
}
but this did not really work since it was then also sorting the names which messed up the scoreboard and it showed the wrong results, number one could be number three for example.
I am still learning so I apologize if my question is silly or my code is "weird"
Thanks
also here is my sorting class:
public class ReverseSort : IComparer
{
public int Compare(object x, object y)
{
return Comparer.Default.Compare(y, x);
}
}
So lstLeaderBoard is just list of integers, so you can safely use integer comparison, the way you did it, it just uses some default comparer on object type, which is far away from integer.
So simple LINQ OrderBy would suffice:
lstLeaderBoard.Items.Add(int.Parse(txtScore.Text));
var sortedItems = lstLeaderBoard.Items.Cast<int>().OrderBy(x => x);
lstLeaderBoard.Items.Clear();
foreach (var item in sortedItems)
lstLeaderBoard.Items.Add(item);
I've been trying to figure out how to remove elements in my ArrayList where the value contains some text string.
My Array could look like this:
[0] "\"MAERSKA.CO\",N/A,N/A,N/A,N/A,N/A,N/A"
[1] "\"GEN.COABB.ST\",N/A,N/A,N/A,N/A,N/A,N/A"
[2] "\"ARCM.ST\",\"Arcam AB\",330.00,330.50,332.00,330.50,330.00"
And my ArrayList is created like this:
string stringToRemove = "NA";
ArrayList rows = new ArrayList(csvData.Replace("\r", "").Split('\n'));
So the question is how I delete all entries that contains "NA".
I have tried the RemoveAt or RemoveAll with several combinations of Contains but i cant seem to get the code right.
I do not want to make a new Array if it can be avoided.
Regards
Flemming
If you want to reduce your ArrayList before instantiate your variable, consider using LINQ:
ArrayList rows = new ArrayList(csvData.Replace("\r", "").Split('\n').Where(r => !r.Contains(stringToRemove)).ToList());
If you want to reduce your ArrayList after instantiation, you can try this:
for (int i = 0; i < rows.Count; i++)
{
var row = (string)rows[i];
if (row.Contains(stringToRemove))
{
rows.RemoveAt(i);
i--;
}
}
The following code creates a list as output containing all strings except "N/A":
var outputs = new List<string>();
foreach (var item in input)
{
var splitted = item.Split(',');
foreach (var splt in splitted)
{
if (splt != "N/A")
{
outputs.Add(splt);
}
}
}
The input is your array.
Trying to read a csv file, and take the first word in the stream, throw it in to a dictionary while the following words get added to a list in that dictionary.
However, I find that (during debugging) when, inside my loop I decide to clear my list, all of the values it had added to the dictionary previously also get cleared. I guess I am mistaken in assuming it makes a copy of the list, it is actually just referencing that same list? Should I be creating a new list with every iteration? Code below:
public class TestScript : MonoBehaviour {
// Use this for initialization
void Start() {
Dictionary<string, List<string>> theDatabase = new Dictionary<string, List<string>>();
string word;
string delimStr = ",.:";
char[] delimiter = delimStr.ToCharArray();
List<string> theList = new List<string>();
using (StreamReader reader = new StreamReader("testComma.csv")) {
while (true) {
//Begin reading lines
string line = reader.ReadLine();
if (line == null) {
break;
}
//Begin splitting lines, adding to array.
string[] split2 = line.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
//Loop to hold the first word in the stream
for(int i = 0; i <= 0; i++) {
word = split2[i];
//loop to hold the following words in to list.
for (int y = 1; y < split2.Length; y++) {
theList.Add(split2[y]);
}
//Add word/list combo in to the database
theDatabase.Add(word, theList);
//clear the list.
theList.Clear();
}
}
}
foreach (KeyValuePair<string, List<string>> pair in theDatabase) {
string keys;
List<string> values;
keys = pair.Key;
values = pair.Value;
print(keys + " = " + values);
}
}
}
The bottom foreach loop is just so I can see the results. Also, any critique is welcome in regards to how this is written, as I'm a beginner.
Yes, you're adding the same object to your dictionary.
You can just change :
theDatabase.Add(word, theList);
To :
theDatabase.Add(word, theList.ToList());
Method ToList() makes shallow copy of your List<T>
C# is pass by reference.
So, theList and the list in your Dictionary are the same object.
The simplest solution is to stop clearing your List and create a new one every time instead:
for(int i = 0; i <= 0; i++) {
List<string> theList = new List<string>(); // it is in a loop now
word = split2[i];
//loop to hold the following words in to list.
for (int y = 1; y < split2.Length; y++) {
theList.Add(split2[y]);
}
//Add word/list combo in to the database
theDatabase.Add(word, theList);
//clear the list.
//theList.Clear(); - not required anymore
}
It is more readable and clear solution: create a list, insert items, paste a list into the dictionary, continue the iteration.
It is also much more performant since there is no List clearing - List<T>.Clear() is a linear operation, which takes O(n) operations.
Yes, as everyone says, lists are reference types. You need to make a copy to avoid the .Clear() clearing all the lists.
You could always write your code like this:
void Start()
{
string delimStr = ",.:";
Dictionary<string, List<string>> theDatabase =
File
.ReadAllLines("testComma.csv")
.Select(line => line.Split(delimStr.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
.ToDictionary(x => x[0], x => x.Skip(1).ToList());
/* foreach here */
}
}
This doesn't have the problem with the list references.
I have an Item object with a property called generator_list (hashset of strings). I have 8000 objects, and for each object, I'd like to see how it's generator_list intersects with every other generator_list, and then I'd like to store the intersection number in a List<int>, which will have 8000 elements, logically.
The process takes about 8 minutes, but only a few minutes with parallel processing, but I don't think I'm doing the parallel part right, hence the question. Can anyone please tell me if and how I need to modify my code to take advantage of the parallel loops?
The code for my Item object is:
public class Item
{
public int index { get; set; }
public HashSet<string> generator_list = new HashSet<string>();
}
I stored all my Item objects in a List<Item> items (8000 elements). I created a method that takes in items (the list I want to compare) and 1 Item (what I want to compare to), and it's like this:
public void Relatedness2(List<Item> compare, Item compare_to)
{
int compare_to_length = compare_to.generator_list.Count;
foreach (Item block in compare)
{
int block_length = block.generator_list.Count;
int both = 0; //this counts the intersection number
if (compare_to_length < block_length) //to make sure I'm looping
//over the smaller set
{
foreach (string word in compare_to.generator_list)
{
if (block.generator_list.Contains(word))
{
both = both + 1;
}
}
}
else
{
foreach (string word in block.generator_list)
{
if (compare_to.generator_list.Contains(word))
{
both = both + 1;
}
}
}
// I'd like to store the intersection number, both,
// somewhere so I can effectively use parallel loops
}
}
And finally, my Parallel forloop is:
Parallel.ForEach(items, (kk, state, index) => Relatedness2(items, kk));
Any suggestions?
Maybe something like this
public Dictionary<int, int> Relatedness2(IList<Item> compare, Item compare_to)
{
int compare_to_length = compare_to.generator_list.Count;
var intersectionData = new Dictionary<int, int>();
foreach (Item block in compare)
{
int block_length = block.generator_list.Count;
int both = 0;
if (compare_to_length < block_length)
{
foreach (string word in compare_to.generator_list)
{
if (block.generator_list.Contains(word))
{
both = both + 1;
}
}
}
else
{
foreach (string word in block.generator_list)
{
if (compare_to.generator_list.Contains(word))
{
both = both + 1;
}
}
}
intersectionData[block.index] = both;
}
return intersectionData;
}
And
List<Item> items = new List<Item>(8000);
//add to list
var dictionary = new ConcurrentDictionary<int, Dictionary<int, int>>();//thread-safe dictionary
var readOnlyItems = items.AsReadOnly();// if you sure you wouldn't modify collection, feel free use items directly
Parallel.ForEach(readOnlyItems, item =>
{
dictionary[item.index] = Relatedness2(readOnlyItems, item);
});
I assumed that index unique.
i used a dictionaries, but you may want to use your own classes
in my example you can access data in following manner
var intesectiondata = dictionary[1]//dictionary of intersection for item with index 1
var countOfintersectionItemIndex1AndItemIndex3 = dictionary[1][3]
var countOfintersectionItemIndex3AndItemIndex7 = dictionary[3][7]
don't forget about possibility dictionary[i] == null
Thread safe collections is probably what you are looking for http://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx.
When working in multithreaded environment, you need to make sure that
you are not manipulating shared data at the same time without
synchronizing access.
the .NET Framework offers some collection classes that are created
specifically for use in concurrent environments, which is what you
have when you're using multithreading. These collections are
thread-safe, which means that they internally use synchronization to
make sure that they can be accessed by multiple threads at the same
time.
Source: Programming in C# Exam Ref 70-483, Objective 1.1: Implement multhitreading and asynchronous processing, Using Concurrent collections
Which are the following collections
BlockingCollection<T>
ConcurrentBag<T>
ConcurrentDictionary<T>
ConcurentQueue<T>
ConcurentStack<T>
If your Item's index is contiguous and starts at 0, you don't need the Item class at all. Just use a List< HashSet< < string>>, it'll take care of indexes for you. This solution finds the intersect count between 1 item and the others in a parallel LINQ. It then takes that and runs it on all items of your collection in another parallel LINQ. Like so
var items = new List<HashSet<string>>
{
new HashSet<string> {"1", "2"},
new HashSet<string> {"2", "3"},
new HashSet<string> {"3", "4"},
new HashSet<string>{"1", "4"}
};
var intersects = items.AsParallel().Select( //Outer loop to run on all items
item => items.AsParallel().Select( //Inner loop to calculate intersects
item2 => item.Intersect(item2).Count())
//This ToList will create a single List<int>
//with the intersects for that item
.ToList()
//This ToList will create the final List<List<int>>
//that contains all intersects.
).ToList();
I have a List<object>, and its first element is a List<double>, I mean:
//----
List <object> lista = new List<object>();
List <double> listain = new List<double>();
Lista.Add(listain);
//---
Now I want to obtain the data that is in lista[0] (this element is the List<double>), but I don't know how to do it; I've tried with a foreach, but that doesn't work with objects.
Any idea?
try,
foreach (double item in lista [0] as List<double>)
{
}
foreach (var item in lista.Cast<List<double>>())
{
}
First, to answer your questions:
You have to cast the first element into the right class
foreach (List<double> doubleList in lista){
foreach(var number in doubleList){
// do whatever you want
}
}
Second, why do you cast your List<double> into and list of objects if you already use templates?
try to define the list like this:
List <object> lista = new List<List<double>>();
It doesn't change the programming but it makes it a lot clearer to understand.
You need to cast that element to your desired datatype. This way.
List<double> col = (List<double>) lista[0];
for (i = 0; i < col.Count; i++)
{
//Do something
}
You need to cast it - so:
var doubleList = (List<double>)objectList[0];
Alternatively if you don't know for definite that it will be of that type, you can do
var doubleList = objectList[0] as List<double>;
if (doubleList != null)
{
// do stuff
}
If the list is only to contain lists of doubles you should use:
var doubleList = List<List<Double>>();
Adding would be like:
var double = 1.1;
var insertList = new List<Double>();
insertList.Add(double);
doubleList.Add(insertList);