Compare 2 dictionaries and return missing values - c#

How would I compare these 2 dictionaries and return only the values missing?
The GetFileListFromBlob() function gets all file names and I'd like to know what is missing from the db.
Or is there a better way to get the missing values from these objects? Should I use different key/ value?
Dictionary<int, string> databaseFileList = new Dictionary<int, string>;
Dictionary<int, string> blobFileList = new Dictionary<int, string>;
int counter = 0;
foreach (string f in GetFileListFromDB())
{
counter++;
databaseFileList.Add(counter, f );
}
counter = 0;
foreach (string f in GetFileListFromBlob())
{
counter++;
blobFileList.Add(counter, f);
}
// How to compare?
Thank you

A HashSet<T> might be what you want (instead of a Dictionary<K,V>) - take this example:
var reference = new HashSet<string> {"a", "b", "c", "d"};
var comparison = new HashSet<string> {"a", "d", "e"};
When you now call ExceptWith on the reference set ...
reference.ExceptWith(comparison);
... the reference set will contain the elements "b" and "c" that do not exist in the comparison set. Note however that the extra element "e" is not captured (swap the sets to get "e" as the missing element) and that the operation modifies the reference set in-place. If that isn't wished for, the Except LINQ operator might be worth investigating, as was already mentioned in another answer.

The way I see it, you don't need counters at first (you can add them later).
You can use System.Collections.Generic.List<> type to go on.
List<int, string> databaseFileList = new List<string>(GetFileListFromDB());
List<int, string> blobFileList = new List<string>(GetFileListFromBlob());
//some code
Now if you want to get all items in both lists you can simply use Concat(...) method to unify them and then use Distinct() method to remove duplicate items:
List<string> allItems = databaseFileList.Concat(blobFileList).Distinct();
Now use Except(...) method to compare collections:
var missingItems1 = allItems .Except(databaseFileList);
//or
var missingItems1 = allItems .Except(blobFileList);
//or
//some other code

private void CompareDictionary()
{
var databaseFileList = new Dictionary<int, string>();
var blobFileList = new Dictionary<int, string>();
databaseFileList.Add(300, "apple");
databaseFileList.Add(500, "windows");
databaseFileList.Add(100, "Bill");
blobFileList.Add(100, "Bill");
blobFileList.Add(200, "Steve");
var result = databaseFileList.Where(d2 => !blobFileList.Any(d1 => d1.Key == d2.Key)).ToList();
}

Related

Best way to hold sets of related elements dynamically added

I have a list of files, and the filenames for those files contain some characters then an underscore, then anything else like so:
test_123.txt
What I'm trying to do is loop through these files, pull out the 'prefix' (the characters up to but not including the _, add the prefix to a list if it's not already in the list, and then add the whole filename as an element of that prefix.
That might be confusing so here's an example:
List of file names:
A_ieie.txt
B_ldld.txt
C_test.txt
A_232.txt
B_file2.txt
C_345.txt
So I am looping through these files and get the prefix like so:
string prefix = fileName.Substring(0, fileName.IndexOf('_'));
Now, I check if that prefix is already in a list of prefixes, and if not, add it:
List<string> prefixes = new List<string>();
if (!prefixes.Contains(prefix))
{
prefixes.Add(prefix);
}
So here's the prefixes that would be added to that list:
A //not yet seen, add it to list
B //not yet seen, add it to list
C //not yet seen, add it to list
A //already seen, don't add
B //already seen, don't add
C //already seen, don't add
Okay the above is easy to do, but what about when I want to add the filenames that share a prefix to a list?
Since these are going to be dynamically added and could be anything, I can't make several lists before hand. I thought about have a List of lists, but is that really the best way to do this? Would a class be ideal?
The end goal of the above example would be something like :
[0][0] = A_ieie.txt //This is the 'A' list
[0][1] = A_232.txt
[1][0] = B_ldld.txt //This is the 'B' list
[1][1] = B_file2.txt
[2][0] = C_test.txt //This is the 'C' list
[2][1] = C_345.txt
Sounds like you want a Dictionary:
var list = new Dictionary<string, List<string>>();
The Key would be the "prefix" and the Value would be a list of strings (the filenames).
EDIT
If you want the list of filenames to be unique, perhaps a HashSet is a better option:
var list = new Dictionary<string, HashSet<string>>();
Sounds like you want a Dictionary>
Then, each list is referenced by a key integer (or use a string to "name" the list):
public Dictionary<string, List<string>> myBookList = new Dictionary<string, List<string>>();
private void addList(string listName, List<string> contents)
{
myBookList.Add(listName, contents);
//direct add
List<string> science_Fiction_Books = new List<string>();
myBookList.Add("Science Fiction", science_Fiction_Books);
myBookList["Science_Fiction"].Add("mytitle.txt");
myBookList["Science_Fiction"][0] = "My book title.txt";
string fileLocation = #"c:\mydirectory\mylists\myBookTitle.txt";
myBookList["Science_Fiction"].Add(System.IO.Path.GetFileName(fileLocation));
//etc.
}
You can use linq to achieve this.
List<string> List = new List<string>() { "A_ieie.txt", "B_ldld.txt", "C_test.txt", "A_232.txt", "B_file2.txt", "C_345.txt" };
Dictionary<string, List<string>> Dict = new Dictionary<string, List<string>>();
Dict = List.GroupBy(x => x.Split('_')[0]).ToDictionary(x => x.Key, x => x.ToList());
How about this:
var textFileNameList =
new List<string>{"A_ieie.txt","B_ldld.txt","C_test.txt",
"A_232.txt","B_file2.txt","C_345.txt"};
var groupedList = textFileNameList.GroupBy(t => t.Split('_')[0])
.Select( t=> new {
Prefix = t.Key,
Files = t.Select( file=> file).ToList()
}).ToList();

Dictionary if Key exist append if not add new element C#

I am having
Dictionary<String, List<String>> filters = new Dictionary<String, List<String>>();
which is having values like country = us. till now I am able to add it when key is not repeated. now when key country is repeated. it is showing that the key is already present.
what I want is How to add multiple values in the same key. I am not able to do it. Please suggest something.
for (int i = 0; i < msgProperty.Value.Count; i++)
{
FilterValue.Add(msgProperty.Value[i].filterValue.Value);
filterColumn = msgProperty.Value[i].filterColumnName.Value;
filters.Add(filterColumn, FilterValue);
}
what I want
country = US,UK
The different types of all your variables are a bit confusing, which won't help you writing the code. I'm assuming you have a Dictionary<string, List<string>> where the key is a "language" and the value is a list of countries for that language, or whatever. Reducing a problem to a minimal set that reproduces the issue is very helpful when asking for help.
Anyway assuming the above, it's as simple as this:
Try to get the dictionary["somelanguage"] key into existingValue.
If it doesn't exist, add it and store it in the same variable.
Add the List<string> to the dictionary under the "somelanguage" key.
The code will look like this:
private Dictionary<string, List<string>> dictionary;
void AddCountries(string languageKey, List<string> coutriesToAdd)
{
List<string> existingValue = null;
if (!dictionary.TryGetValue(languageKey, out existingValue))
{
// Create if not exists in dictionary
existingValue = dictionary[languageKey] = new List<string>()
}
existingValue.AddRange(coutriesToAdd);
}
You simply need to check whether the value exists in the dictionary, like this:
if (!filters.ContainsKey("country"))
filters["country"] = new List<string>();
filters["country"].AddRange("your value");
Assuming you are trying to add value for key country
List<string> existingValues;
if (filters.TryGetValue(country, out existingValues))
existingValues.Add(value);
else
filters.Add(country, new List<string> { value })
If your values is List<string>
List<string> existingValues;
if (filters.TryGetValue(country, out existingValues))
existingValues.AddRange(values);
else
filters.Add(country, new List<string> { values })
Make use of IDictionary interface.
IDictionary dict = new Dictionary<String, List<String>>();
if (!dict.ContainsKey("key"))
dict["key"] = new List<string>();
filters["key"].Add("value");

Adding new element within a list inside a dictionary

In a dictionary, I want to add a list of numbers for a given key.But I am unable to do it.
for(int i = 0 ; i < size ; i++){
string input = Console.ReadLine();
string[] inputList = input.Split(' ');
count[Convert.ToInt32(inputList[0])]++;
if(!map.ContainsKey(Convert.ToInt32(inputList[0]))){
map.Add(Convert.ToInt32(inputList[0]),new List<string>());
map_index.Add(Convert.ToInt32(inputList[0]),new List<int>());
}
}
The question is bit unclear. My understanding of your problem is as follows: You have a dictionary, a value of the dictionary is a list, and you have trouble adding an item to that list. Since you didn't explain your notation I'm using more general names, just to give you an idea what has to be done:
Dictionary<int, List<string>> myDict = new Dictionary<int, List<string>>();
if (myDict.ContainsKey(myKey))
{
myDict[myKey].Add(myVal);
}
else
{
myDict[myKey] = new List<string> { myVal };
}
If the key is not in the dictionary you create an entry together with the list and initialize the list with the new value. If the key is there you just access the list (by using myDict[myKey]) and add the new value to the list. Since the list is always created for a new key you don't have to worry that it's not initialized when adding a value for an existing key.
This could be one the efficient Solution and much easier than if-else.
Dictionary<int, List<string>> myDict = new Dictionary<int, List<string>>();
try
{
myDict[myKey].Add(myVal);
}
catch
{
myDict[myKey] = new List<string> { myVal };
}
There is a 'one-command-line' way to do this using AddOrUpdate from ConcurrentDictionary:
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
...
var dictionary = new ConcurrentDictionary<int, string[]>();
var itemToAdd = "item to add to key-list";
dictionary.AddOrUpdate(1, new[]{item1ToAdd}, (key, list) => list.Append(itemToAdd));
// If key 1 doesn't exist, creates it with a list containing itemToAdd as value
// If key 1 exists, adds item to already existent list (third parameter)

Making a List<string> from Dictionary<string, string>

I was wondering if it were possible to make a list from the dictionary values where the key is a specified value?
The dictionary would like this:
Sidcup - DPC1
Sidcup - DPC2
Blackheath - DPC3
Blackheath - DPC4
Bexleyheath - DPC5
In fact, I'm not entirely implementing a Dictionary as above is a good idea. Here is its implementation:
DataSet ds = EngineBllUtility.GetDPCsForImportFile(connectionString, fileID);
if (ds.Tables.Count > 0)
{
DataTable dtDPCs = EngineBllUtility.GetDPCsForImportFile(connectionString, fileID).Tables[0];
Dictionary<string, string> preliminaryList = new Dictionary<string, string>();
if (dtDPCs.Columns.Contains("DPCNumber") && dtDPCs.Columns.Contains("BranchName"))
foreach (DataRow dataRow in dtDPCs.Rows)
{
preliminaryList.Add(dataRow["BranchName"].ToString(), dataRow["DPCNumber"].ToString());
}
I have the following code: (Excuse the last line, its just so you have an idea of what I'm trying to do).
foreach (string branch in branchNames)
{
string subfolder = System.IO.Path.Combine(saveLocation, branch);
System.IO.Directory.CreateDirectory(subfolder);
List<string> certificateList = new List<string>();
certificateList.Add(DPCNumber in preliminaryList where Key = branch);
}
In the above the branch is the key from the Dictionary. I need to iterate through because it needs to create a new folder and then do something with the certificateList I am creating.
Sure:
private static void TestZip()
{
Dictionary<string, string> stringstringdic = new Dictionary<string, string>();
stringstringdic.Add("1", "One");
stringstringdic.Add("2", "Two");
stringstringdic.Add("3", "Three");
stringstringdic.Add("4", "Four");
stringstringdic = stringstringdic.Where(pair => pair.Key != "1")
.ToDictionary(pair => pair.Key, pair => pair.Value);
List<string> stringlist = stringstringdic.Keys.Concat(stringstringdic.Values).ToList();
foreach (string str in stringlist)
{
Console.WriteLine(str);
}
}
//Output:
//2
//3
//4
//Two
//Three
//Four
Of course, you'll have to change the Where clause to reflect your real need.
If I understood you right, it's like .Where(pair => pair.Key == branch)
If I understand you correctly you want to add the value based on a key to a separate List?
certificateList.Add(preliminaryList[branch])
This is simplified as I really need to see the declaration of preliminaryList to know how DPCNumber fits into all of it. Could it be...
certificateList.Add(preliminaryList[branch].ToString())
To simply create a list of keys you can do the following.
var dictionary = new Dictionary<string, string>();
dictionary.Add("key1", "value1");
dictionary.Add("key2", "value2");
dictionary.Add("key3", "value3");
dictionary.Add("key4", "value4");
dictionary.Add("key5", "value5");
var list = dictionary.Keys.ToList();
This should give you a list with values "key1", "key2", "key3", "key4", "key5".
You can put a where clause in to filter out certain keys. The following gives all keys which contain a "2" (random example), resulting in just "key2".
var filteredList = dictionary.Keys.Where(key => key.Contains("2")).ToList();
Edit:
To get a value given a specific key.
string value = dictionary["key1"];
Note, the key is a dictionary must be unique, so for a given key you will only ever get a single value back and not a list of values.

c# How to sort a sorted list by its value column

i have a generic sorted list "results" with key = some filename and value = boolean.
I would like to sort the list by the boolean entry or value column. does anyone know how i can do this?
Thanks!
SortedList is optimized so that inertions occur in an ordered fashion, such that enumeration occurs in a sorted order at minimal cost. Anything else requires a re-sort. Thus:
SortedList<string,bool> l = new SortedList<string, bool>();
l.Add("a", true);
l.Add("b", false);
l.Add("c", true);
l.Add("d", false);
var orderByVal = l.OrderBy(kvp => kvp.Value);
but this enumeration will be significantly slower to calculate, and be performed up-front, requiring extra storage to do so.
Depending on your situation it might be cheaper to maintain 2 SortedList instances with the key/value reversed.
In .NET 2.0, you could add your items to a SortedList:
public static List<MyObject> SortedObjects(IEnumerable<MyObject> myList) {
SortedList<string, MyObject> sortedList = new SortedList<string, MyObject>();
foreach (MyObject object in myList) {
sortedList.Add(object.ValueIWantToSort, object);
}
return new List<MyObject>(sortedList.Values);
}
For descending all list items
list.OrderByDescending();
or
var list = list.OrderByDescending(x => x.Product.Name)
.ThenBy(x => x.Product.Price).ToList();
Normally that sorted by the first key on the list so if you swap the key and value on the add, then match that on the binding
that sample example i use and work fine
public static SortedList<string, string> GetCountries(string conn)
{
var dict = new SortedList<string, string>();
dict.Add("","Select One");
var sql = "SELECT [CountryID] ,[Descr] FROM [dbo].[Countries] Order By CountryID ";
using (var rd = GetDataReader(conn, sql))
{
while (rd.Read())
{
dict.Add(rd["Descr"].ToString(), rd["CountryID"].ToString());
}
}
return dict;
}
Dim List As SortedList(Of String, String) = VDB.CoreLib.DbUtils.GetCountries(connDB)
ddlBankCountry.DataSource = List
ddlBankCountry.DataTextField = "Key"
ddlBankCountry.DataValueField = "Value"
ddlBankCountry.DataBind()

Categories