Can a ComboBox accommodate both numbers and text? - c#

I am trying to figure out something. I have a method which adds some items into a ComboBox named "cbSize". I realize that if I add two types of data into it, the code will crash. Is this because a ComboBox can only accommodate one type of data?
items.Add(1);
items.Add(10);
items.Add(100);
items.Add(2);
items.Add(20);
items.Add(3);
items.Add(30); //works fine if add numbers only
//items.Add("4"); //will crash if mix both numbers and text
//items.Add("2"); //works fine if add text only
//then sort them out
items.Sort();
//now clear original cbSize items
cbSize.Items.Clear();
//and add them back in sorted order
cbSize.Items.AddRange(items.ToArray());
//gotta clear ArrayList for the next time or else things will add up
items.Clear();

Is this because a ComboBox can only accommodate one type of data?
No, try below it will work
cbSize.Items.Add("44");
cbSize.Items.Add(44);
problem is with your items collection, it is type safe. you can't add different types to it.
try with list of objects. it will work. reason is both int and string are objects
List<object> items = new List<object>();
items.Add(1);
items.Add(30);
items.Add("4");
items.Add("2");
//since you have string and int value you need to create custom comparer
items.Sort((x, y) => Convert.ToInt32(x).CompareTo(Convert.ToInt32(y)));
//now clear original cbSize items
cbSize.Items.Clear();
//and add them back in sorted order
cbSize.Items.AddRange(items.ToArray());
OR you can use ArrayList class (not type-safe because it can store any object)
var integers = new ArrayList();
integers.Add(1);
integers.Add(2);
integers.Add("3");
comboBox1.Items.AddRange(integers.ToArray());
What is type-safe in .net?

Yes. What you can do is to provide a Size class that will adapt from ints and strings:
items.Add(new Size(3));
items.Add(new Size(4));
items.Add(new Size("large"));
Then, you could make the Size class implement IComparable so you can call the Sort() method.

Related

How to get Many enum sources in the same ListBox

I have these enums that i am trying to get into the same ListBox.
public enum Mammals
{
BlueWhale,
Monkey
}
public enum Reptiles
{
Lizzard,
Python
}
List <object> allAnimals =new List<object>();
animals_lbx.DataSource = allAnimals;
To get one of the lists into the listbox i could simply write:
animals_lbx.DataSource( Enum.GetValues(typeof(Mammals));
but how do i get the both Enum-sources in the same ListBox?
One way is to use
ListBox.Items.AddRange
Adds a group of items to the list of items for a ListBox.
animals_lbx.Items.AddRange(Enum.GetValues(typeof(Mammals));
animals_lbx.Items.AddRange(Enum.GetValues(typeof(Reptiles));
Update
oops, you will need to cast it, as Enum.GetValues returns an System.Array and AddRange expects an object[]
listBox1.Items.AddRange(Enum.GetValues(typeof(Mammals)).Cast<object>().ToArray());

How to access a list with an index from a calling function

I am writing a c# console program.
I have a function that returns a list of objects.
e.g the following will return a list of objects.
p.getList();
If I already know the index of the object I want to reference from the list, then how to I access this?
For example I want to do the following which obviously is incorrect:
p.getList()[Index]
This would give me the item in the list at index.
To get around this I have done the following:
List<MyObject> mylist = p.getList();
mylist[Index];
but the above seems inefficient, to have to create a copy just to reference a value.
Any tips on how I can access?
Thanks.
If you don't want the list, but an item and you know the Index then
var item = p.getList()[Index];
syntax is perfectly correct. Please, notice, that List<T> is a reference type, that's why in case of
var list = p.getList(); // reference copy, not the collection cloning
var item = list[Index];
...
var otherItem = list[otherIndex];
the var list = p.getList(); adds a miniscule overhead: it's reference, not the entire collection is being copied.

nested hashset of lists?

I'm working on one of the project Euler problems, and I wanted to take the approach of creating a list of values, and adding the list to a Hashset, this way I could evaluate in constant time if the list already exists in the hashset, with the end goal to count the number of lists in the hashset for my end result.
The problem I'm having is when I create a list in this manner.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
finalList.Add(candidate);
if (finalList.Contains(candidate) == false) finalList.Add(candidate);
candidate.Clear();
//try next value
Obviously the finalList[0] item is cleared when I clear the candidate and is not giving me the desired result. Is it possible to have a hashset of lists(of integers) like this? How would I ensure a new list is instantiated each time and added as a new item to the hashset, perhaps say in a for loop testing many values and possible list combinations?
Why don't you use a value which is unique for each list as a key or identifier? You could create a HashSet for your keys which will unlock your lists.
You can use a Dictionary instead. The only thing is you have to test to see if the Dictionary already has the list. This is easy to do, by creating a simple class that supports this need.
class TheSimpleListManager
{
private Dictionary<String, List<Int32>> Lists = new Dictionary<String, List<Int32>>();
public void AddList(String key, List<Int32> list)
{
if(!Lists.ContainsKey(key))
{
Lists.Add(key, list);
}
else
{
// list already exists....
}
}
}
This is just a quick sample of an approach.
To fix your clear issue: Since its an object reference, you would have to create a new List and add it to the HashSet.
You can create the new List by passing the old one into its constructor.
HashSet<List<int>> finalList = new HashSet<List<int>>();
List<int> candidate = new List<int>();
candidate.Add(5);
var newList = new List<int>(candidate);
finalList.Add(newList);
if (finalList.Contains(newList) == false) //Not required for HashSet
finalList.Add(newList);
candidate.Clear();
NOTE: HashSet internally does a contains before adding items. In otherwords, here even if you execute finalList.Add(newList); n times, it would add newList only once. Therefore it is not necessary to do a contains check.

C# .NET List declaration.Size unknown

I have to declare a list and use it in my code.How ever the number of elements that i will add to list will vary during each time I run my code.So how can I create a list and add elements to it dynamically with out specifying its size during declaration?
var myList = new List<string>();
myList.Add("foo");
myList.Add("blah");
// and on and on ...
List's in .Net will automatically resize themselves as you add to them.
You don't have to specify the bounds of a list (as you do with arrays). You can keep on calling Add() method to add elements in the list. You can create either a generic list which takes only specified types of objects and a non-generic list that only takes objects:
Generic:
List<int> intList = new List<int>();
intList.Add(10);
intList.Add(20);
Non-Generic:
ArrayList objList = new ArrayList();
objList.Add(New Employee());
objList.Add(20);
objList.Add("string");
The later can take any type of object but is not type-safe.
The System.Collection namespace is full of collection classes that can dynamically contract and expand its size, see the Generic namespace for the most used classes: http://msdn.microsoft.com/en-us/library/system.collections.generic.aspx
I recommend sticking with a List if you doubt what you are doing:
var list = new List<string>();
list.Add("test1");
list.Add("test2");
list.Remove("test1");

C# Sort List Based on Another List

I have a class that has multiple List<> contained within it. Its basically a table stored with each column as a List<>. Each column does not contain the same type. Each list is also the same length (has the same number of elements).
For example:
I have 3 List<> objects; one List, two List, and three List.
//Not syntactically correct
List<DateTime> one = new List...{4/12/2010, 4/9/2006, 4/13/2008};
List<double> two = new List...{24.5, 56.2, 47.4};
List<string> three = new List...{"B", "K", "Z"};
I want to be able to sort list one from oldest to newest:
one = {4/9/2006, 4/13/2008, 4/12/2010};
So to do this I moved element 0 to the end.
I then want to sort list two and three the same way; moving the first to the last.
So when I sort one list, I want the data in the corresponding index in the other lists to also change in accordance with how the one list is sorted.
I'm guessing I have to overload IComparer somehow, but I feel like there's a shortcut I haven't realized.
I've handled this design in the past by keeping or creating a separate index list. You first sort the index list, and then use it to sort (or just access) the other lists. You can do this by creating a custom IComparer for the index list. What you do inside that IComparer is to compare based on indexes into the key list. In other words, you are sorting the index list indirectly. Something like:
// This is the compare function for the separate *index* list.
int Compare (object x, object y)
{
KeyList[(int) x].CompareTo(KeyList[(int) y])
}
So you are sorting the index list based on the values in the key list. Then you can use that sorted key list to re-order the other lists. If this is unclear, I'll try to add a more complete example when I get in a situation to post one.
Here's a way to do it using LINQ and projections. The first query generates an array with the original indexes reordered by the datetime values; in your example, the newOrdering array would have members:
{ 4/9/2006, 1 }, { 4/13/2008, 2 }, { 4/12/2010, 0 }
The second set of statements generate new lists by picking items using the reordered indexes (in other words, items 1, 2, and 0, in that order).
var newOrdering = one
.Select((dateTime, index) => new { dateTime, index })
.OrderBy(item => item.dateTime)
.ToArray();
// now, order each list
one = newOrdering.Select(item => one[item.index]).ToList();
two = newOrdering.Select(item => two[item.index]).ToList();
three = newOrdering.Select(item => three[item.index]).ToList();
I am sorry to say, but this feels like a bad design. Especially because List<T> does not guarantee element order before you have called one of the sorting operations (so you have a problem when inserting):
From MSDN:
The List is not guaranteed to be
sorted. You must sort the List
before performing operations (such as
BinarySearch) that require the List
to be sorted.
In many cases you won't run into trouble based on this, but you might, and if you do, it could be a very hard bug to track down. For example, I think the current framework implementation of List<T> maintains insert order until sort is called, but it could change in the future.
I would seriously consider refactoring to use another data structure. If you still want to implement sorting based on this data structure, I would create a temporary object (maybe using an anonymous type), sort this, and re-create the lists (see this excellent answer for an explanation of how).
First you should create a Data object to hold everything.
private class Data
{
public DateTime DateTime { get; set; }
public int Int32 { get; set; }
public string String { get; set; }
}
Then you can sort like this.
var l = new List<Data>();
l.Sort(
(a, b) =>
{
var r = a.DateTime.CompareTo(b);
if (r == 0)
{
r = a.Int32.CompareTo(b);
if (r == 0)
{
r = a.String.CompareTo(b);
}
}
return r;
}
);
I wrote a sort algorithm that does this for Nito.LINQ (not yet released). It uses a simple-minded QuickSort to sort the lists, and keeps any number of related lists in sync. Source code starts here, in the IList<T>.Sort extension method.
Alternatively, if copying the data isn't a huge concern, you could project it into a LINQ query using the Zip operator (requires .NET 4.0 or Rx), order it, and then pull each result out:
List<DateTime> one = ...;
List<double> two = ...;
List<string> three = ...;
var combined = one.Zip(two, (first, second) => new { first, second })
.Zip(three, (pair, third) => new { pair.first, pair.second, third });
var ordered = combined.OrderBy(x => x.first);
var orderedOne = ordered.Select(x => x.first);
var orderedTwo = ordered.Select(x => x.second);
var orderedThree = ordered.Select(x => x.third);
Naturally, the best solution is to not separate related data in the first place.
Using generic arrays, this can get a bit cumbersome.
One alternative is using the Array.Sort() method that takes an array of keys and an array of values to sort. It first sorts the key array into ascending order and makes sure the array of values is reorganized to match this sort order.
If you're willing to incur the cost of converting your List<T>s to arrays (and then back), you could take advantage of this method.
Alternatively, you could use LINQ to combine the values from multiple arrays into a single anonymous type using Zip(), sort the list of anonymous types using the key field, and then split that apart into separate arrays.
If you want to do this in-place, you would have to write a custom comparer and create a separate index array to maintain the new ordering of items.
I hope this could help :
one = one.Sort(delegate(DateTime d1, DateTime d2)
{
return Convert.ToDateTime(d2).CompareTo(Convert.ToDateTime(d1));
});

Categories

Resources