c# search arraylist problem - c#

In my code I have an arraylist, called heart, which contains numbers from 1-13.
heart.Add("any");
for(int i = 0; i < 14; i++)
{
heart.Add(i);
}
As you can see it also contains "any" placed in the first element. When I use this code to get the all of the elements that has a value over 5 I get an error.
int store = heart.Cast<int>().Where(item => item > 5).Count().ToString();
I get the error "Specified cast is not valid" and that's because of the
"any" I have in the first element. Could anyone help me fix this?

It sounds like you just need the OfType method instead:
string store = heart.OfType<int>().Where(item => item > 5).Count().ToString();
OfType only returns values which are of the approriate type, ignoring others. See my Edulinq blog post on it for more information.
As Sven shows, you can also use the overload of Count which takes a predicate, to remove the Where call:
string store = heart.OfType<int>().Count(item => item > 5).ToString();
(I've changed the variable type given that you're calling ToString at the end... again, you may want to think about this decision. It depends on how you're using it of course.)
However, I'd strongly advise you to use a strongly-typed collection instead of ArrayList. Think about what the collection is meant to hold - it seems odd to hold both strings and integers. What are you trying to do with it?

Use this instead:
int count = heart.OfType<int>().Count(item => item > 5);
OfType will filter the list and return only those elements that are the correct type, rather than Cast which tries to cast all elements.

You can't cast the word "any" to an integer, that's pretty straight forward.
We'd have to know exactly what your trying to do with here, and how the array is used to really give a good recommendation.

Since you're using int and you wanted values of 1-13, may I suggest you use an int value of 0 to represent 'any'?

You could do
Int store = heart.GetRange(1, heart.Count - 1).Cast<int>().Where(item => item > 5).Count().ToString();

Related

Getting a list item by index

I've recently started using c# moving over from Java. I can't seem to find how to get a list item by index. In java to get the first item of the list it would be:
list1.get(0);
What is the equivalent in c#?
list1[0];
Assuming list's type has an indexer defined.
You can use the ElementAt extension method on the list.
For example:
// Get the first item from the list
using System.Linq;
var myList = new List<string>{ "Yes", "No", "Maybe"};
var firstItem = myList.ElementAt(0);
// Do something with firstItem
Visual Basic, C#, and C++ all have syntax for accessing the Item property without using its name. Instead, the variable containing the List is used as if it were an array:
List[index]
See, for instance, List.Item[Int32] Property.
.NET List data structure is an Array in a "mutable shell".
So you can use indexes for accessing to it's elements like:
var firstElement = myList[0];
var secondElement = myList[1];
Starting with C# 8.0 you can use Index and Range classes for accessing elements. They provides accessing from the end of sequence or just access a specific part of sequence:
var lastElement = myList[^1]; // Using Index
var fiveElements = myList[2..7]; // Using Range, note that 7 is exclusive
You can combine indexes and ranges together:
var elementsFromThirdToEnd = myList[2..^0]; // Index and Range together
Also you can use LINQ ElementAt method but for 99% of cases this is really not necessary and just slow performance solution.
Old question, but I see that this thread was fairly recently active, so I'll go ahead and throw in my two cents:
Pretty much exactly what Mitch said. Assuming proper indexing, you can just go ahead and use square bracket notation as if you were accessing an array. In addition to using the numeric index, though, if your members have specific names, you can often do kind of a simultaneous search/access by typing something like:
var temp = list1["DesiredMember"];
The more you know, right?
you can use index to access list elements
List<string> list1 = new List<string>();
list1[0] //for getting the first element of the list

C# linked lists

very basic question, but is there any ToArray-like function for c# linked lists that would return an array of only part of the elements in the linkedlist.
e.g.: let's say my list has 50 items and I need an array of only the first 20. I really want to avoid for loops.
Thanks,
PM
Use Linq?
myLinkedList.Take(20).ToArray()
or
myLinkedList.Skip(5).Take(20).ToArray()
You say you "really want to avoid for loops" - why?
If you're using .NET 3.5 (or have LINQBridge), it's really easy:
var array = list.Take(20).ToArray();
... but obviously that will have to loop internally.
Note that this will create a smaller array if the original linked list has fewer than 20 elements. It's unclear whether or not that's what you want.
Something is going to have to loop internally, sooner or later - it's not like there's going to be a dedicated CPU instruction for "navigate this linked list and copy a fixed number of pointers into a new array". So the question is really whether you do it or a library method.
If you can't use LINQ, it's pretty easy to write the equivalent code yourself:
int size = Math.Min(list.Count, 20);
MyType[] array = new MyType[size];
var node = list.First;
for (int i = 0; i < size; i++)
{
array[i] = node.Value;
node = node.Next;
}
That will actually be slightly more efficient than the LINQ approach, too, because it creates the array to be exactly the right size to start with. Yes, it uses a loop - but as I say, something's got to.
If you're using the LinkedList collection class (from System.Collections.Generic), you can use LINQ to get it:
var myArray = list.Take(20).ToArray();

In what order does a C# for each loop iterate over a List<T>?

I was wondering about the order that a foreach loop in C# loops through a System.Collections.Generic.List<T> object.
I found another question about the same topic, but I do not feel that it answers my question to my satisfaction.
Someone states that no order is defined. But as someone else states, the order it traverses an array is fixed (from 0 to Length-1). 8.8.4 The foreach statement
It was also said that the same holds for any standard classes with an order (e.g. List<T>). I can not find any documentation to back that up. So for all I know it might work like that now, but maybe in the next .NET version it will be different (even though it might be unlikely).
I have also looked at the List(t).Enumerator documentation without luck.
Another related question states that for Java, it is specifically mentioned in the documentation:
List.iterator()returns an iterator over the elements in this list
in proper sequence."
I am looking for something like that in the C# documentation.
Thanks in advance.
Edit: Thank you for all you for all your answers (amazing how fast I got so many replies). What I understand from all the answers is that List<T> does always iterate in the order of its indexing. But I still would like to see a clear peace of documentation stating this, similar to the Java documentation on List.
Basically it's up to the IEnumerator implementation - but for a List<T> it will always go in the natural order of the list, i.e. the same order as the indexer: list[0], list[1], list[2] etc.
I don't believe it's explicitly documented - at least, I haven't found such documentation - but I think you can treat it as guaranteed. Any change to that ordering would pointlessly break all kinds of code. In fact, I'd be surprised to see any implementation of IList<T> which disobeyed this. Admittedly it would be nice to see it specifically documented...
On Microsoft Reference Source page for List<T> Enumerator it is explicitly stated that the iteration is done from 0 to Length-1:
internal Enumerator(List<T> list) {
this.list = list;
index = 0;
version = list._version;
current = default(T);
}
public bool MoveNext() {
List<T> localList = list;
if (version == localList._version && ((uint)index < (uint)localList._size))
{
current = localList._items[index];
index++;
return true;
}
return MoveNextRare();
}
Hope it's still relevant for somebody
In your link, the accepted answer states in C# Language Specification Version 3.0, page 240:
The order in which foreach traverses
the elements of an array, is as
follows: For single-dimensional arrays
elements are traversed in increasing
index order, starting with index 0 and
ending with index Length – 1. For
multi-dimensional arrays, elements are
traversed such that the indices of the
rightmost dimension are increased
first, then the next left dimension,
and so on to the left. The following
example prints out each value in a
two-dimensional array, in element
order:
using System;
class Test
{
static void Main() {
double[,] values = {
{1.2, 2.3, 3.4, 4.5},
{5.6, 6.7, 7.8, 8.9}
};
foreach (double elementValue in values)
Console.Write("{0} ", elementValue);
Console.WriteLine();
}
}
The output produced is as follows:
1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9 In the example
int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int, the element type of numbers.
The order is defined by the iterator being used to traverse a collection of data using a foreach loop.
If you are using a standard collection that is indexable (such as a List), then it will traverse the collection starting with index 0 and moving up.
If you need to control the ordering you can either control how the iteration of the collection is handled by implementing your own IEnumerable, or you can sort the list the way you want it before executing the foreach loop.
This explains how Enumerator works for generic List. At first the current element is undefined and uses MoveNext to get to the next item.
If you read MoveNext it indicates that it will start with the first element of the collection and from there move to the next one until it reaches the end of the collection.
I've just had to do something similar as a quick hack of code, though it didn't work for what I was trying to do it did reorder the list for me.
Using LINQ to change the order
DataGridViewColumn[] gridColumns = new DataGridViewColumn[dataGridView1.Columns.Count];
dataGridView1.Columns.CopyTo(gridColumns, 0); //This created a list of columns
gridColumns = (from n in gridColumns
orderby n.DisplayIndex descending
select n).ToArray(); //This then changed the order based on the displayindex
Lists seem to return the items in an order they are in the backing store--so if they are added to the list that way they'll be returned that way.
If your program depends on the ordering, you may want to sort it before traversing the list.
It's somewhat silly for linear searches--but if you need the order a certain way your best bet is make the items in that order.

Customizing Sort Order of C# Arrays

This has been bugging me for some time now. I've tried several approaches and none have worked properly.
I'm writing and IRC client and am trying to sort out the list of usernames (which needs to be sorted by a users' access level in the current channel).
This is easy enough. Trouble is, this list needs to added to whenever a user joins or leaves the channel so their username must be removed the list when the leave and re-added in the correct position when they rejoin.
Each users' access level is signified by a single character at the start of each username. These characters are reserved, so there's no potential problem of a name starting with one of the symbols. The symbols from highest to lowest (in the order I need to sort them) are:
~
&
#
%
+
Users without any sort of access have no symbol before their username. They should be at the bottom of the list.
For example: the unsorted array could contain the following:
~user1 ~user84 #user3 &user8 +user39 user002 user2838 %user29
And needs to be sorted so the elements are in the following order:
~user1 ~user84 &user8 #user3 %user29 +user39 user002 user2838
After users are sorted by access level, they also need to be sorted alphabetically.
Asking here is a last resort, if someone could help me out, I'd very much appreciate it.
Thankyou in advance.
As long as the array contains an object then implement IComparable on the object and then call Array.Sort().
Tho if the collection is changable I would recommend using a List<>.
You can use SortedList<K,V> with the K (key) implementing IComparable interface which then defines the criteria of your sort. The V can simply be null or the same K object.
You can give an IComparer<T> or a Comparison<T> to Array.Sort. Then you just need to implement the comparison yourself. If it's a relatively complex comparison (which it sounds like this is) I'd implement IComparer<T> in a separate class, which you can easily unit test. Then call:
Array.Sort(userNames, new UserNameComparer());
You might want to have a convenient instance defined, if UserNameComparer has no state:
Array.Sort(userNames, UserNameComparer.Instance);
List<T> has similar options for sorting - I'd personally use a list rather than an array, if you're going to be adding/removing items regularly.
In fact, it sounds like you don't often need to actually do a full sort. Removing a user doesn't change the sort order, and inserting only means inserting at the right point. In other words, you need:
Create list and sort it to start with
Removing a user is just a straightforward operation
Adding a user requires finding out where to insert them
You can do the last step using Array.BinarySearch or List.BinarySearch, which again allow you to specify a custom IComparer<T>. Once you know where to insert the user, you can do that relatively cheaply (compared with sorting the whole collection again).
You should take a look at the IComparer interface (or it's generic version). When implementing the CompareTo method, check whether either of the two usernames contains one of your reserved character. If neither has a special reserved character or both have the same character, call the String.CompareTo method, which will handle the alphabetical sorting. Otherwise use your custom sorting logic.
I gave the sorting a shot and came up with the following sorting approach:
List<char> levelChars = new List<char>();
levelChars.AddRange("+%#&~".ToCharArray());
List<string> names = new List<string>();
names.AddRange(new[]{"~user1", "~user84", "#user3", "&user8", "+user39", "user002", "user2838", "%user29"});
names.Sort((x,y) =>
{
int xLevel = levelChars.IndexOf(x[0]);
int yLevel = levelChars.IndexOf(y[0]);
if (xLevel != yLevel)
{
// if xLevel is higher; x should come before y
return xLevel > yLevel ? -1 : 1;
}
// x and y have the same level; regular string comparison
// will do the job
return x.CompareTo(y);
});
This comparison code can just as well live inside the Compare method of an IComparer<T> implementation.

Array of an unknown length in C#

I've just started learning C# and in the introduction to arrays they showed how to establish a variable as an array but is seems that one must specify the length of the array at assignment, so what if I don't know the length of the array?
Arrays must be assigned a length. To allow for any number of elements, use the List class.
For example:
List<int> myInts = new List<int>();
myInts.Add(5);
myInts.Add(10);
myInts.Add(11);
myInts.Count // = 3
Use List<> to build up an 'array' of unknown length.
Use List<>.ToArray() to return a real array, and not a List.
var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
var array = list.ToArray();
A little background information:
As said, if you want to have a dynamic collection of things, use a List<T>. Internally, a List uses an array for storage too. That array has a fixed size just like any other array. Once an array is declared as having a size, it doesn't change. When you add an item to a List, it's added to the array. Initially, the List starts out with an array that I believe has a length of 16. When you try to add the 17th item to the List, what happens is that a new array is allocated, that's (I think) twice the size of the old one, so 32 items. Then the content of the old array is copied into the new array. So while a List may appear dynamic to the outside observer, internally it has to comply to the rules as well.
And as you might have guessed, the copying and allocation of the arrays isn't free so one should aim to have as few of those as possible and to do that you can specify (in the constructor of List) an initial size of the array, which in a perfect scenario is just big enough to hold everything you want. However, this is micro-optimization and it's unlikely it will ever matter to you, but it's always nice to know what you're actually doing.
You can create an array with the size set to a variable, i.e.
int size = 50;
string[] words = new string[size]; // contains 50 strings
However, that size can't change later on, if you decide you need 100 words. If you need the size to be really dynamic, you'll need to use a different sort of data structure. Try List.
Use an ArrayList if in .NET 1.x, or a List<yourtype> if in .NET 2.0 or 3.x.
Search for them in System.Collections and System.Collections.Generics.
You might also want to look into Dictionarys if your data is unique, This will give you two columns to work with.
User name , Total bill
it gives you a lot of built in tools to search and update just the value.
var yummy = new List<string>();
while(person.FeelsHappy()) {
yummy.Add(person.GetNewFavoriteFood());
}
Console.WriteLine("Sweet! I have a list of size {0}.", list.Count);
Console.WriteLine("I didn't even need to know how big to make it " +
"until I finished making it!");
try a generic list instead of array
In a nutshell, please use Collections and Generics.
It's a must for any C# developer, it's worth spending time to learn :)
As detailed above, the generic List<> is the best way of doing it.
If you're stuck in .NET 1.*, then you will have to use the ArrayList class instead. This does not have compile-time type checking and you also have to add casting - messy.
Successive versions have also implemented various variations - including thread safe variants.
If you really need to use an array instead of a list, then you can create an array whose size is calculated at run time like so...
e.g i want a two dimensional array of size n by n. n will be gotten at run time from the user
int n = 0;
bool isInteger = int.TryParse(Console.ReadLine(), out n);
var x = new int[n,n];

Categories

Resources