Remove First & Last Items from a List of string - c#

Have a Dictionary <string,string> as follows.
var d = new Dictionary<string, string>
{
{ "d.b.f", "x1" },
{ "d.z.x.f", "x2" },
{ "d.y.f.x.f", "x3" }
};
Want to construct a new Dictionary with first (d) & last (f) excluded from each key in dictionary. So result looks
var res = new Dictionary<string, string>
{
{ "b", "x1" },
{ "z.x", "x2" },
{ "y.f.x", "x3" }
};
I tried as follows.
var abc = d.Select(x => Helper(x));
private static KeyValuePair<string,string> Helper(KeyValuePair<string,string> x)
{
var array = x.Key.Split('.').ToList();
return new KeyValuePair<string, string>(string.Join(".", array.Where(z => array.IndexOf(z) != 0 && array.IndexOf(z) != array.Count - 1)), x.Value);
}
now abc has my required result. Is there an efficient way to do the same thing?

If you know that you will always have d. in front, and .f on the end, you could simply do a substring of your key.
private static KeyValuePair<string, string> Helper(KeyValuePair<string, string> x)
{
// starting index of 2, to skip "d.", and length of the key minus "d." and ".f"
var substring = x.Key.Substring(2, x.Key.Length - 4);
return new KeyValuePair<string, string>(substring, x.Value);
}
Alternatively, if you will actually have more characters in front and behind (instead of just d. and .f), you could calculate the index of the first . and last . and then create a substring from that:
private static KeyValuePair<string, string> Helper(KeyValuePair<string, string> x)
{
// d.b.f
var startIndex = x.Key.IndexOf('.') + 1; // 2
var endIndex = x.Key.LastIndexOf('.'); // 3
var length = endIndex - startIndex; // 1
var substring = x.Key.Substring(startIndex, length); // b
return new KeyValuePair<string, string>(substring, x.Value);
}

Related

how to set Number from 0 to increment 1,2,,... etc for combine dictionary

I have 2 dictionaries where Number = 0 for all items,
var dict1 = new Dictionary<string, Test>
{
{ "Key1", new Test { Number = 0, Name = "Name1" } },
{ "Key2", new Test { Number = 0, Name = "Name2" } },
{ "Key3", new Test { Number = 0, Name = "Name3" } }
};
var dict2 = new Dictionary<string, Test>
{
{ "Key1", new Test { Number = 0, Name = "Name1" } },
{ "Key4", new Test { Number = 0, Name = "Name4" } }
};
Now after eliminating duplicate key/value pairs, in combined dictionary result I want to set Number = 1, 2, 3,... how to do this?
var combine = dict1.Union(dict2)
.GroupBy(kvp => kvp.Key)
.Select(grp => grp.First())
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
You can do
var n = 0;
and then do it functionally but not very efficiently in your case. The function will select all items from your dictionary and create a new collection with updated values, which is then converted to a dictionary.
var newDict = dict2.Select(d => new Test { Number = ++n, Name = d.Value[1].Name }).ToDictionary();
Or with a good old loop:
foreach(var d in dict2)
{
d.Value[0].Number = n++;
}
As suggested by the comment. If you want to start off with 0, use
n++;
if with 1, use
++n;
Try this:
int i = 0;
var combine = dict1.Union(dict2)
.GroupBy(kvp => kvp.Key)
.OrderBy(kvp => kvp.Key)
.ToDictionary(kvp => kvp.Key, kvp => new Test() { Number = ++i, Name = kvp.First().Value.Name });
It should give you this:
{ "Key1", new Test { Number = 1, Name = "Name1" } },
{ "Key2", new Test { Number = 2, Name = "Name2" } },
{ "Key3", new Test { Number = 3, Name = "Name3" } }
{ "Key4", new Test { Number = 4, Name = "Name4" } }
I think you're trying to combine dictionaries, and then assign to Number the count of duplicate items.
You might consider putting all the dictionaries into a list and iterating over each item and putting it in a combined result dictionary. If the item already exists in the result then increment the Number property.
Initial setup:
public class Test
{
public int Number { get; set; }
public string Name { get; set; }
}
var dict1 = new Dictionary<string, Test>
{
{ "Key1", new Test { Number = 0, Name = "Name1" } },
{ "Key2", new Test { Number = 0, Name = "Name2" } },
{ "Key3", new Test { Number = 0, Name = "Name3" } }
};
var dict2 = new Dictionary<string, Test>
{
{ "Key1", new Test { Number = 0, Name = "Name1" } },
{ "Key4", new Test { Number = 0, Name = "Name4" } }
};
// Put the dictionaries you want to combine into one list:
var all = new List<Dictionary<string, Test>>();
all.Add(dict1);
all.Add(dict2);
// Declare result dictionary
var combine = new Dictionary<string, Test>();
Set up is done, this is the main loop you want:
foreach (var dict in all)
{
foreach (var kvp in dict)
{
if (combine.ContainsKey(kvp.Key))
{
combine[kvp.Key].Number++;
}
else
{
combine.Add(kvp.Key, kvp.Value);
}
}
}
Interactive shell output:
Dictionary<string, Submission#0.Test>(4) {
{ "Key1", Submission#0.Test { Name="Name1", Number=1 } },
{ "Key2", Submission#0.Test { Name="Name2", Number=0 } },
{ "Key3", Submission#0.Test { Name="Name3", Number=0 } },
{ "Key4", Submission#0.Test { Name="Name4", Number=0 } }
}
There is an overload of Select extension which provides index as well (MSDN)
var combine = dict1.Union(dict2)
.GroupBy(kvp => kvp.Key)
.Select((grp,index) => new { Key = grp.Key, Value = new Test { Number = index+1, Name = grp.First().Name}})
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
You can loop through the keys
int n = 1;
foreach (string key in combine.Keys) {
combine[key].Number = n++;
}
The keys are not returned in order. If you want to number them in order:
int n = 1;
var orderedKeyValuePairs = combine
.OrderBy(kvp => kvp.Key, StringComparer.CurrentCultureIgnoreCase);
foreach (var kvp in orderedKeyValuePairs) {
kvp.Value.Number = n++;
}
Note that you can only access the Number like this if Test is a reference type (class). If Test was a struct, you would have to re-assign the whole struct because the dictionary would return a copy of the value.
The optional StringComparer argument allows you to specify different string comparison modes:
Ordinal, OrdinalIgnoreCase, CurrentCulture, CurrentCultureIgnoreCase
If you want to sort by name:
int n = 1;
var orderedValues = combine.Values
.OrderBy(v => v.Name, StringComparer.CurrentCultureIgnoreCase);
foreach (var v in orderedValues) {
v.Number = n++;
}
Looping over the key-value-pairs or values also has the advantage that you can change the value directly, whereas when looping through the keys (as in my first code snippet), you must look up the dictionary, which is less performing.

How to separate the string and value to dictionary?

I have a comma separated string with values as follows:
"File_name,cost_per_page,0.23,color_code,343,thickness,0.01".
I want to read cost_per_page = 0.23, color_code=343 and thickness=0.01.
How can I do this? I could do this by putting it to a list and reading successive element next to key string. Is there any other method?
The simplest (and therefor, probably the best) approach would be to simply use string.Split and then iterate the array:
var source = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
var splitted = source.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries)
var result = new Dictionary<string, string>();
// Note: Starting from 1 to skip the "file_name"
// moving 2 indexes in each iteration,
// and ending at length - 2.
for(int i = 1; i < splitted.Length - 1; i+=2)
{
result.Add(splitted[i], splitted[i+1]);
}
I've tried to find a clever way to do it with linq, but the best I came up with is really not that clever at all:
var valuesWithIndexes = source
.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries)
.Skip(1)
.Select((v, i) => new {v, i});
var keys = valuesWithIndexes.Where(x => x.i % 2 == 0);
var values = valuesWithIndexes.Where(x => x.i % 2 == 1);
var dictionary = keys.Zip(values, (k, v) => new {k, v})
.ToDictionary(key => key.k,
val => val.v);
I think the simple for loop is a clear winner in this case.
I think that this is the simplest and best approach.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, double> dict = new Dictionary<string, double>();
for (int i = 1; i < array.Length - 1; i = i + 2)
{
string key = array[i];
double value = Double.Parse(array[i + 1], CultureInfo.InvariantCulture);
dict.Add(key, value);
}
You can also use the above code for a larger string (variable str has more key-value pairs).
I'd use linq.
Convert the string into a delimited array.
Set up a dictionary containing the first item...not sure if you want to do this. If not just remove the "d1" and "union" statements.
Run some Linq to create your dictionary based on even numbers.
Then if you really want to account for the first item, file_name, and you want that at the beginning of your dictionary then lastly you'd run the "union" statement.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, string> d1 = new Dictionary<string, string>()
{
{ array[0], "" }
};
Dictionary<string, string> d2 = array.Select((i, index) => (index > 0 && index % 2 == 0) ?
new { key = array[index - 1], value = i } : null).Where(i => i != null).ToDictionary(d => d.key, d => d.value);
Dictionary<string, string> result = d1.Union(d2).ToDictionary(k => k.Key, v => v.Value);
foreach (KeyValuePair<string, string> kvp in result)
Console.WriteLine(kvp.Key + ": " + kvp.Value);
return;
another, and probably cleaner approach:
This accounts for File_name as well. If you don't want it then add "index > 0" to the conditional operator where it checks for even.
string str = "File_name,cost_per_page,0.23,color_code,343,thickness,0.01";
string[] array = str.Split(',');
Dictionary<string, string> d2 = array.Select((i, index) => (index % 2 == 0) ?
new
{
key = (index == 0) ? i : array[index - 1],
value = (index == 0) ? "" : i
} : null).Where(i => i != null).ToDictionary(d => d.key, d => d.value);
foreach (KeyValuePair<string, string> kvp in d2)
Console.WriteLine(kvp.Key + ": " + kvp.Value);
Full working example in this fiddle.
All you need is to iterate while you haven't reached your string array end ensuring your index increments by 2 (field name, field value).
int i = 1;
var temp = s.Split(',').ToList();
while(i < temp.Count) {
i = i+2;
}

How to get the nearest key to a specified number in a dictionary?

I have an Excel function which I'm trying to translate to C# equivalent code. The function (in Excel) is as follows:
WorksheetFunction.VLookup(number, Range("numberDictionary"), 2, True)
Essentially what this function does is...
Assuming a dictionary exists, defined as follows:
Number | Value
1 | 2
3 | 8
9 | 1
And assuming that my parameter 'number' equals 2
I would expect a Value returned of 8, as the lookup function would round my input number 2 up to the nearest number in the range (3) and then return the associated value.
Can anyone tell me how I might achieve the same thing in C# code? Assuming the use of a Dictionary<int, int>()
Many thanks in advance
Ian
You can leverage the Keys property of IDictionary<TKey, TValue>:
var dictionary = new Dictionary<int, int> { { 1, 2 }, { 3, 8 }, { 9, 1 } };
var key = dictionary.Keys.Where(a => a >= 2).OrderBy(a => a).First();
var value = dictionary[key];
var input = 2;
var dictionary = new Dictionary<int, int> { { 1, 2 }, { 3, 8 }, { 9, 1 } };
var smallestDifference = int.MaxValue;
var keys = new List<int>();
if (dictionary.ContainsKey(input))
{
return dictionary[input];
}
foreach (var entry in dictionary)
{
var difference = entry.Key - input;
if (difference < smallestDifference)
{
smallestDifference = difference;
keys = new List<int>() { entry.Key };
}
else if (difference == smallestDifference)
{
keys.Add(entry.Key);
}
}
var candidates = dictionary.Where(x => x.Key == smallestDifference).ToList();
if ( candidates.Count == 1)
{
return candidates.SingleOrDefault();
}
return candidates.SingleOrDefault(y => y > input);
If you insist on a dictionary you could use following LINQ query:
Dictionary<int, int> dictionary = new Dictionary<int, int>() {
{1,2} ,{3,8} ,{9,1}
};
int searchKey = 2;
int value;
if (dictionary.ContainsKey(searchKey))
value = dictionary[searchKey];
else
{
int nearestKey = dictionary.Keys
.Select(i => new { Value = i, Diff = Math.Abs(i - searchKey) })
.OrderBy(x => x.Diff)
.ThenBy(x => x.Value > searchKey ? 0 : 1) // in case of ties you want the higher number
.Select(x => x.Value)
.First();
value = dictionary[nearestKey];
}
this would be O(n) since you have to look at all keys. If you could use an ordered collection and a binary search algorithm it would be O(log n). So you could use a SortedDictionary<TKey, TValue> or SortedList<TKey, TValue>. Differences
With a SortedList you could use this extension method. Then it's simple:
int index = dictionary.FindFirstIndexGreaterThanOrEqualTo(2);
int value = dictionary[dictionary.Keys[index]];

After removing an item from a Dictionary, how to change the other keys accordingly?

For example, a dictionary contains,
key: 1 2 3 4 5
value: a b c d e
Once you delete the item b, the dictionary would looks like this,
key: 1 3 4 5
value: a c d e
However, I want the key to be like so,
key: 1 2 3 4
value: a c d e
Is there any possible way to do this?
You want an Array or a List, not a dictionary.
If you want to keep it as a dictionary, you could convert it to a list, then remove the entry, then reconvert it back to a dictionary.
var list = new List<string>();
foreach(var item in dictionary)
{
list.Add(item.Value);
}
var newDict = new Dictionary<int, string>();
for(int i = 1; i < list.Count + 1; i++)
{
newDict.Add(i,list[i]);
}
Don't do this though.
As others have said, this is not the right approach. However, it is possible. Here's another way:
public static void Test()
{
var foo = new Dictionary<int, string> { { 1, "a" }, { 2, "b" }, { 3, "c" }, { 4, "d" }, { 5, "e" } };
RemoveItemByKey(ref foo, 3);
RemoveItemByValue(ref foo, "a");
foreach (var kvp in foo)
{
Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
}
// Output:
// 1: b
// 2: d
// 3: e
}
public static void RemoveItemByValue(ref Dictionary<int, string> dictionary, string valueToRemove)
{
foreach (var kvp in dictionary.Where(item=>item.Value.Equals(valueToRemove)).ToList())
{
RemoveItemByKey(ref dictionary, kvp.Key);
}
}
public static void RemoveItemByKey(ref Dictionary<int, string> dictionary, int keyToRemove)
{
if (dictionary.ContainsKey(keyToRemove))
{
dictionary.Remove(keyToRemove);
int startIndex = 1;
dictionary = dictionary.ToDictionary(keyValuePair => startIndex++, keyValuePair => keyValuePair.Value);
}
}

get combination from a list of key-values

I have a dict<string, list<string>>, say 3 keys in dict, the first key has 2 values, the secodn 3 values, the third key has 3 values. If I get a value from each value set, then I will have a combination of 2*3*3 = 18 sets
How to code in c#?
thanks
Edit
Sorry did not make it clear
I want something like this
say I have dict like this
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3", new List<string>() {"f", "g"}
I want output like this
acf, acg, adf, adg, aef, aeg
bcf, bcg, bdf, bdg, bef, beg
With Linq:
var dict = new Dictionary<String, List<String>>() {
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3",new List<String>(){"f", "g", "h"}},
};
var combis = from kv in dict
from val1 in kv.Value
from val2 in kv.Value
select string.Format("{0}{1}", val1, val2);
foreach (var combi in combis)
Console.WriteLine(combi);
demo: http://ideone.com/nm7mY
Quick & dirty but you may polish this method. The result list contains expected result:
Usage:
var dict = new Dictionary<String, List<String>>() {
{"1",new List<String>(){"a", "b"}},
{"2",new List<String>(){"c", "d", "e"}},
{"3",new List<String>(){"f", "g"}},
};
var collections = dict.Select(kvp => kvp.Value).ToArray();
var result = new List<string>();
GetNextProduct(collections, 0, String.Empty, result);
Method that produces the result:
private static void GetNextProduct(IEnumerable<string>[] collections, int collectionIndex, string currentProduct, IList<string> results)
{
var currentList = collections[collectionIndex];
bool isLast = collections.Length == collectionIndex + 1;
foreach (var s in currentList)
{
if (isLast) results.Add(currentProduct + s);
else GetNextProduct(collections, collectionIndex + 1, currentProduct + s, results);
}
}
I think you mean this?
Dictionary<string, int> dict = new Dictionary<string, int>
{
{ "Hello World", 1 },
{ "HelloWorld", 1 },
{ "Hello World", 1 },
};
foreach (var item in dict) // var is of type KeyValuePair<string, int>
Console.WriteLine(item.Key + ", " + item.Value);
Dictionary<string, List<int>> storage = new Dictionary<string, List<int>>();
storage.Add("key1", new List<int>() { 2, 7 });
storage.Add("key2", new List<int>() { 8, 4, 1});
storage.Add("key3", new List<int>() { 3, 9, 3 });
foreach (string key in storage.Keys)
{
//access to single storage...
List<int> subStorage = (List<int>)storage[key];
foreach (int item in subStorage)
{
//access to single value inside storage...
}
}
I would try something like the following if I was trying to read or edit the values in the lists:
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();
var arrayOfValues = dict.Values.ToArray();
for (int i = 0; i < arrayOfValues.Length; i++)
{
for (int j = 0; j < arrayOfValues[i].Count; j++)
{
//read/edit arrayOfValues[i][j];
}
}
You do not need recursion since you know the dept of the "tree".

Categories