473,394 Members | 1,718 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

foreach with options?

I have a collection which I need to navigate through in several different
ways. Is there any way to structure my class such that I can have several
different iterators?

Ideally, I'd like to do something like:

// Iterate whole collection
foreach (object in collection)

// Iterate over all objects with the "open" flag set
foreach (object in collection.opennodes)

// Iterate over all blue objects
foreach (object in collection.bluenodes)

Is there some way I can do this? The underlying collection is a generic
dictionary, so I understand that I need to handle the selection logic. My
brain is telling me that I need to set flags that control the foreach loop
before I enter it, but that seems to archaic. I will know in advance how
many different types of iterator I will need.

Any suggestions?
Thanks
Steve
Mar 14 '06 #1
3 2419


Steve Barnett wrote:
I have a collection which I need to navigate through in several different
ways. Is there any way to structure my class such that I can have several
different iterators?
Yes, give it properties returning different views:

class MyClass: ICollection<Foo> {
ICollection<Foo> AllNodes { get { return this; } }
ICollection<Foo> BlueNodes { get { return /* something else */; } }
}

Which would allow you to rewrite to:
Ideally, I'd like to do something like:

// Iterate whole collection
foreach (object in collection)
foreach( object o in myClassIntances )

or

foreach( object o in myClassIntances.AllNodes )

// Iterate over all objects with the "open" flag set
foreach (object in collection.opennodes)
foreach ( object o in myClassInstance.OpenNodes )

// Iterate over all blue objects
foreach (object in collection.bluenodes)


My general suggestion is to write a "filter-dictionary", so you can simply:

Dictionary<Foo,Bar> dict = ...;
foreach ( Foo foo in
new FilterCollection(
dict.Keys,
delegate(Foo x) { return x.isBlue(); })
...;

If you often do the same transformation, give it a name:

public static ICollection<Foo> BlueNodes(ICollection<Foo> nodes) {
return new FilterCollection(
node,
delegate(Foo x) { return x.isBlue(); });
}

and if your "masert-dictionary" collection should supply callers with
different views, as suggested at the top of this post:

public class MyDict: IDictionary<Foo, Bar> {
...
ICollection Foo BlueKeys { get { return BlueNodes(Keys); } }
}

Here as an implementation suggestion:

/// <summary>
/// Filters an ICollection to only contains the values satisfying a
predicate
/// </summary>
public class FilterCollection<T> : ICollection<T>
{
public ICollection<T> Parent;
public delegate bool FilterFunction(T t);
public FilterFunction Filter;
public FilterCollection(ICollection<T> parent, FilterFunction
filter)
{
this.Parent = parent;
this.Filter = filter;
}
public int Count
{
get
{
int count = 0;
foreach (T t in Parent)
if (Filter(t))
++count;
return count;
}
}
public bool IsReadOnly { get { return Parent.IsReadOnly; } }
public void Add(T item)
{
if (!Filter(item))
throw new ArgumentException(string.Format("Filter
rejected {0}", item));
else
Parent.Add(item);
}
public void Clear() { throw new Immutable(this); }
public bool Contains(T item) { return Parent.Contains(item) &&
Filter(item); }
public void CopyTo(T[] array, int arrayIndex)
{
foreach (T t in this)
array[arrayIndex++] = t;
}
public bool Remove(T item) { return Filter(item) &&
Parent.Remove(item); }
public IEnumerator<T> GetEnumerator()
{
foreach (T t in Parent)
if (Filter(t))
yield return t;
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

/// <summary>
/// Filters an IDictionary to only contain the entries satisfying a
predicate
/// </summary>
public class FilterDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
public IDictionary<TKey, TValue> Parent;
public delegate bool FilterFunction(TKey key, TValue value);
public FilterFunction Filter;
public FilterDictionary(IDictionary<TKey, TValue> parent,
FilterFunction filter)
{
this.Parent = parent;
this.Filter = filter;
}
public virtual TValue this[TKey key]
{
get
{
TValue val = Parent[key];
if (Filter(key, val))
return val;
else
throw new KeyNotFoundException(string.Format("Not
accepted by filter: {0}->{1}", key, val));
}
set
{
if (Filter(key, value))
Parent[key] = value;
else
throw new KeyNotFoundException(string.Format("Not
accepted by filter: {0}", key));
}
}
protected bool keyFilter(TKey key) { return Filter(key,
Parent[key]); }
public ICollection<TKey> Keys { get { return new
FilterCollection<TKey>(Parent.Keys, keyFilter); } }
public ICollection<TValue> Values { get { throw new
NotImplementedException("Pending need for implementation"); } }
public int Count { get { return Keys.Count; } }
public bool IsReadOnly { get { return Parent.IsReadOnly; } }
public bool ContainsKey(TKey key)
{
TValue val;
return TryGetValue(key, out val);
}
public void Add(TKey key, TValue value)
{
if (!Filter(key, value))
throw new ArgumentException(string.Format("Filter
rejected {0}=>{1}", key, value));
Parent.Add(key, value);
}
public bool Remove(TKey key)
{
TValue val;
return TryGetValue(key, out val) && Parent.Remove(key);
}
public bool TryGetValue(TKey key, out TValue value) { return
Parent.TryGetValue(key, out value) && Filter(key, value); }
public void Add(TKey item) { throw new
NotSupportedException("Cannot add key-only"); }
public void Clear() { throw new
NotSupportedException(string.Format("Cannot clear {0}", GetType())); }
public bool Contains(TKey item) { return ContainsKey(item); }
public void CopyTo(TKey[] array, int arrayIndex) {
this.Keys.CopyTo(array, arrayIndex); }
public IEnumerator<TKey> GetEnumerator()
{ return Keys.GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { throw new
NotImplementedException(); }
public DictionaryKeyValuePairCollection<TKey, TValue>
AsCollection(IEqualityComparer<TValue> comparer)
{ return new DictionaryKeyValuePairCollection<TKey,
TValue>(this, comparer); }
public DictionaryKeyValuePairCollection<TKey, TValue> AsCollection()
{ return new DictionaryKeyValuePairCollection<TKey, TValue>(this); }
IEnumerator<KeyValuePair<TKey, TValue>>
IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{ return AsCollection().GetEnumerator(); }
public bool Remove(KeyValuePair<TKey, TValue> kvp)
{ return AsCollection().Remove(kvp); }
public bool Contains(KeyValuePair<TKey, TValue> kvp)
{ return AsCollection().Contains(kvp); }
public void Add(KeyValuePair<TKey, TValue> kvp)
{ AsCollection().Add(kvp); }
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
{ AsCollection().CopyTo(array, index); }
}
}
--
Helge Jensen
mailto:he**********@slog.dk
sip:he**********@slog.dk
-=> Sebastian cover-music: http://ungdomshus.nu <=-
Mar 14 '06 #2
> I have a collection which I need to navigate through in several
different ways. Is there any way to structure my class such that I can
have several different iterators?

Ideally, I'd like to do something like:

// Iterate whole collection
foreach (object in collection)
// Iterate over all objects with the "open" flag set
foreach (object in collection.opennodes)
// Iterate over all blue objects
foreach (object in collection.bluenodes)


It depends really. If you got a simple way of extracting a new collection
containing only the nodes you're interested in then I suggest you go with
that. For instance, if you got a dictionary or other type of index giving
you simple access to your nodes based on some criteria value, then that might
be the best solution.

Otherwise, if you're using .NET 2.0 you can take advantage of the new enumerator
syntax and write simple methods. For instance, here is the one for the blue
nodes loop:

public class YourCollection
{
....
public IEnumerable<Node> BlueNodes()
{
foreach (Node n in this)
if (n.IsBlue)
yield return n;
}
....
}

then you can simply use it like this:

foreach (Node n in yourCol.BlueNodes())
....

this will of course internally eat through your whole collection but the
above two lines of code will only see the blue ones. You can extrapolate
the rest of your criteria from this.

if you need the same in .NET 1.x then I'm afraid you need to build a class
implementing the IEnumerable interface and internally do the same kind of
check in the MoveNext method. If you need an example of such a solution then
respond here and I'll give it a shot.

--
Lasse Vågsæther Karlsen
http://usinglvkblog.blogspot.com/
mailto:la***@vkarlsen.no
PGP KeyID: 0x2A42A1C2

Mar 14 '06 #3
Helge & Lasse,
Many thanks for this. I thought it would be far more complicated than
this (and was on the verge of giving up).

Very much appreciated.
Steve


"Lasse Vågsæther Karlsen" <la***@vkarlsen.no> wrote in message
news:a0*************************@news.microsoft.co m...
I have a collection which I need to navigate through in several
different ways. Is there any way to structure my class such that I can
have several different iterators?

Ideally, I'd like to do something like:

// Iterate whole collection
foreach (object in collection)
// Iterate over all objects with the "open" flag set
foreach (object in collection.opennodes)
// Iterate over all blue objects
foreach (object in collection.bluenodes)


It depends really. If you got a simple way of extracting a new collection
containing only the nodes you're interested in then I suggest you go with
that. For instance, if you got a dictionary or other type of index giving
you simple access to your nodes based on some criteria value, then that
might be the best solution.

Otherwise, if you're using .NET 2.0 you can take advantage of the new
enumerator syntax and write simple methods. For instance, here is the one
for the blue nodes loop:

public class YourCollection
{
...
public IEnumerable<Node> BlueNodes()
{
foreach (Node n in this)
if (n.IsBlue)
yield return n;
}
...
}

then you can simply use it like this:

foreach (Node n in yourCol.BlueNodes())
...

this will of course internally eat through your whole collection but the
above two lines of code will only see the blue ones. You can extrapolate
the rest of your criteria from this.

if you need the same in .NET 1.x then I'm afraid you need to build a class
implementing the IEnumerable interface and internally do the same kind of
check in the MoveNext method. If you need an example of such a solution
then respond here and I'll give it a shot.

--
Lasse Vågsæther Karlsen
http://usinglvkblog.blogspot.com/
mailto:la***@vkarlsen.no
PGP KeyID: 0x2A42A1C2

Mar 14 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Mountain Man | last post by:
Hi, I'm having trouble with the foreach function. I'm using it twice inside a user defined function with two different arrays, and in the second instance it's returning the value of the first...
12
by: Patrick Russell | last post by:
I am trying to figure out why the code listed below works in php v4.3.0 but not in v4.3.10: $string = "Param1=Val1;Param2=Val2;Param3=Val3"; $exploded_string = explode(";",$string);...
10
by: Elementary Penguin | last post by:
is there a way to decrement a foreach loop? for example string s = "cat"; foreach(char c in s) //some how it goes backward here Console.WriteLine(c);
8
by: mike | last post by:
what should i have to write in this code section? #### is what i want to write do i have to use foreach to for if options is TextBox array i used to enumbera....... but i don't...
15
by: Fabio Cannizzo | last post by:
Is it possible to do something similar to the STL iterators, i.e. to execute a foreach loop in reverse order? Thanks, Fabio
2
by: John Dalberg | last post by:
In a traditional for loop, one can use the index (say i) and continue looping in another function and come back to original for loop (even though it's not good practice) Can the newer foreach...
1
by: Dave | last post by:
Hello, What is the best way (performance wise) to search for a row in a table? Let say I have a column named "col1" and what to get the row that the value of "col1" is "It is me"... I can set...
7
by: Tony Johansson | last post by:
Hello! Why does not this cause a compile error because a ulong has never been implicitly convertible to byte? ulong vektor = {100000,200000,300000}; foreach(byte b in vektor) {...
4
by: mattehz | last post by:
Hey there, I am trying to upload old source files and came across these errors: Warning: Invalid argument supplied for foreach() in /home/mattehz/public_html/acssr/trunk/inc_html.php on line 59...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.