using ...
string[] myFiles = Directory.GetFiles(FilePathIn, "*.dat", SearchOption.TopDirectoryOnly);
I am getting a list of files returned. Alongside this I want to keep a set of int flags. I am about to do this by creating a tuple list eg List<Tuple<int, string>> then looping through myfiles adding each to the tuple list.
Although this will work I wondered if there was a cleaner way to do this? It doesn't have to be a tuple list. It just needs to be an ordered list of the files with a flag
If you are interested in just iteration then a list of some compound type is the way to go -- you can use a custom struct instead of a Tuple to increase readability or a custom class if you intend for the flags to be mutable later on, but the general idea is the same.
You can also use a Dictionary<string, int> of filenames to flags; this has the advantage that it allows quick lookups if you have a filename in hand.
Finally, consider using a [Flags] enum instead of a bare integer to hold the flags you need.
Depending on how you want to use the data later, I would either map the filenames to the integers (Dictionary<string, int>) or the integers to files. I assume two files can have the same "flag", so I would use either a Dictionary<int, List<string>> or constuct IGrouping<int, string> or ILookup<int, string>. It's a shame really that .NET BCL doesn't contain a straightforward mutable Multimap (or Lookup) that you could use like a dictionary.
Why you don't use dictionary to access an element in a dictionary it will cost O(1)
Dictionary<int,string> myFilesOrderedDict = new Dictionary<int,string>();
Or if you want to groupfile by an int as a flag you can do the inverse as I don't think that the name of the file can be repeated twice
Something like this
//string will be the name of the file
Dictionary<string ,int> myFilesOrderedDict = new Dictionary<string,int>();
Hope this help
You can create an anonymous type:
var filesWithFlags = Directory.GetFiles(..)
.Select(f => new {File = f, Flags = 123});
And use the result like this:
foreach (var fileWithFlags in filesWithFlags)
{
DoSomethingWith(fileWithFlags.File);
AndDoSomethingWith(fileWithFlags.Flags);
}
Related
I have a dictionary which holds strings as keys and Lists as values. Imagine you have Olympic Games where the keys are different countries and the values in each list are for example number of participants, number of sports, gold medals, silver medals, etc. So if I want to sort the countries by gold medals and say gold medals is the second entry in each list I would want something like this:
var countryRankings = new Dictionary<string, List<int>>();
countryRankings.Add(country, new List<int>() {numberOfParticipants, numberOfWins });
//some more country data follows
countryRankings.OrderByDescending(pairs => pairs.Value[1]);
The last bit is not rejected by VisualStudio but is not working as expected. The dictionary is not sorted.When I think about it it's better to create class country with different properties and then sort with Lambda in the way OrderBy(c => c.goldMedals) but is there a way to do this with nested inside a dictionary List ?
That's because the OrderByDescending extension method does not mutate (modify) the original object (countryRankings) but instead returns another object that, when enumerated, produces ordered references to elements in the original dictionary.
So, this should work:
var orderedRankings = countryRankings.OrderByDescending(pairs => pairs.Value[1]);
// now you can iterate over orderedRankings
foreach(var rankingPair in orderedRankings)
{
// do something with it..
}
And, yes it would be better to create a class as you suggested in the last part of the question but that doesn't change the answer.
The OrderByDescending method doesn't sort the dictionary, it returns a new collection that is sorted.
Assign the result to a variable. It can't be a dictionary though, as the items in a dictionary can't be reordered. You can use the ToList method to realise the result as an actual collection:
List<KeyValuePair<string, List<int>>> result =
countryRankings.OrderByDescending(pairs => pairs.Value[1]).ToList();
Using a class instead of a list of integers would be better, but it doesn't change what you need to do to get the sorted result, only what the expression to sort it looks like.
I'm looking for a way to define a dictionary for reuse. ie. I can create the dictionary object without having to populate it with the values I want.
Here is what I have currently (note code not tested, just example)
public Dictionary<string, string> NewEntryDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
// populate key value pair
foreach(string name in Enum.GetNames(typeof(Suits))
{
dic.Add(name, "");
}
return dic;
}
The end result should be a new dictionary object with a predefined set of keys.
But I want to avoid doing it this way.
It's not really clear whether you're concerned about the amount of code you've written, or the efficiency of it. From an efficiency perspective, it's fine - it's O(N), but that's hard to avoid if you're populating a dictionary with N entries.
You can definitely make the source code shorter though, using LINQ:
public Dictionary<string, string> NewEntryDictionary()
{
return Enum.GetNames(typeof(Suits)).ToDictionary(name => name, name => "");
}
That won't be any more efficient, of course... it's just shorter code.
If you do ONLY want to save values according to your enum, use
Dictionary<Suits,String> instead of Dictionary<String,String>
Everything else, Jon already said. Use LinQ for a bit more "fancy" look. But that does not do better performance
What I need is something like an array but letting me to assign an element to whatever an index at any time and check if there is already a value assigned to particular index approximately like
MyArray<string> a = new MyArray<string>();
a[10] = "ten";
bool isTheFifthElementDefined = a[5] != null; // false
Perhaps Dictionary<int, string> with its ContainsKey method could do, but isn't there a more appropriate data structure if I want an ordered collection with numeric keys only?
I am also going to need to iterate through the defined elements (with foreach or linq preferably) accessing both the value and the key of current element.
As you mentioned Dictionary seems more appropriate for this.But you can do it with generic lists,for example, when you are creating your list you can specify an element count,and you can give a default temporary value for all your elements.
List<string> myList = new List<string>(Enumerable.Repeat("",5000));
myList[2300] = "bla bla bla..";
For int:
List<int> myList = new List<int>(Enumerable.Repeat(0,5000));
For custom type:
List<MyClass> myList = new List<MyClass>(Enumerable.Repeat(new MyClass(), 100));
Ofcourse It is not the best solution...
Note: Also you can use SortedList instead of Dictionary if you want an ordered collection by keys:
SortedList<TKey, TValue> : Represents a collection of key/value pairs that are sorted by key based on the associated IComparer implementation.
If you need key/value pairs you cannot use a list, you'll need a Dictionary.
The implementation is pretty snappy so don't be too afraid about performance (as long as you don't put too much values in it).
You can iterate over it with
foreach(KeyValuePair<int, string> kvp in dict)
{
}
If you need to order it you can use a list:
List<int> ordered = new List(dict.Keys);
ordered.Sort();
foreach(int key in ordered)
{
}
I'm trying to locate all the keys in one Dictionary that are not in another Dictionary. Obviously, I can do this using a nested loop, but I'm trying to learn LINQ at the moment and I was wondering if I might use it to accomplish this task?
Here's what I have so far:
Dictionary<string, List<string>> DBtables = this.CollectTableListings();
var generic = from Dictionary<string,List<string>> tab
in DBtables
where !_tables.ContainsKey(???)
select tab;
Any idea what should go in place of the question marks (or perhaps instead of the entire where clause)?
You can do:
var resultKeys = DBTables.Keys.Except( _tables.Keys );
The Except() method is essentially the same as the minus operations in SQL - it returns all items from the first collection excluding those in the second. Since dictionaries expose their keys, you can compute their difference that way.
The Except() operator uses the default equality for the type, but there is also an overload which allows you to specify your own IEqualityComparer to override the semantics of how to compare values. In your example, you probably don't need that - but it's nice to know it there.
Dictionary<string, List<string>> dictOne = ...
Dictionary<string, List<string>> dictTwo = ...
var missingKeys = dictOne.Keys.Where(x => !dictTwo.ContainsKey(x));
Dictionary<string, List<string>> dictionary = this.CollectTableListings();
Dictionary<string, List<string>> otherDictionary = getOtherTable();
var keys = from key in dictionary.Keys
where !otherDictionary.Keys.Contains(key)
select key;
(But LBuskin's answer is much better)
have a look at the Except extension method. HTH.
If you wanted to use query syntax I would do something akin to below:
var keys = from d1 in dictionary1
select d1.Key;
var items = from d2 in dictionary2
where d2.Key in keys
select d2;
foreach(var item in items)
{
}
Suppose I have a Dictionary like so:
Dictionary<string, Stream>
How can I get a list (or IEnumerable or whatever) of JUST the Keys from this dictionary? Is this possible?
I could enumerate the dictionary, and extract the keys one by one, but I was hoping to avoid this.
In my instance, the Dictionary contains a list of filenames (file1.doc, filex.bmp etc...) and the stream content of the file from another part of the application.
KeyCollection Dictionary(TKey, TValue).Keys
Dictionary(TKey, TValue).Keys
Typically you can discover these things through code-completion/IntelliSense.
Similarly, there is a Values property:
Dictionary<T,T>.Keys returns a KeyCollection. This has the IEnumerable interface.
so...
foreach(string key in Dictionary<string,Stream>.Keys)
{
}
public IEnumerable<long> ReturnSomeKeys()
{
var foo = new Dictionary<long, string>();
return foo.Keys;
}
This does what you want.