I need to split a custom string into the following format using C#.
The following string: AD=Demo,OU=WEB,OU=IT,L=MyCity,C=MyCountry, i want to split it at comma into a
List<CustomDictionary> myList = new
List<CustomDictionary>();
Based on the text above and after the split, the myList list should contain 5 objects of type CustomDictionary.
object1.Key = AD
object1.Value = Demo
object2.Key = OU
object2.Value = WEB
object3.Key = OU
object3.Value = IT
object4.Key = L
object4.Value = MyCity
object5.Key = C
object5.Value = MyCountry
Here is the CustomObject class
public class CustomDictionary
{
public string Key { get; set; }
public string Value { get; set; }
public CustomDictionary(string key, string value)
{
this.Key = key;
this.Value = value;
}
}
So far I tried this:
Here I am stuck!
List<CustomDictionary> keyVal = new List<CustomDictionary>val.Split(',').Select(x=>x.Split('=')).Select(x=>x.));
where val is the actual string ...
With linq:
var query = from x in str.Split(',')
let p = x.Split('=')
select new CustomDictionary(p[0], p[1]);
var list = query.ToList();
Also seems like you want to get a dictionary as a result. If so, try this code:
var dict = str.Split(',').Select(x => x.Split('='))
.ToDictionary(x => x[0], x => x[1]);
To handle duplicate keys, you can store objects in Lookup. Just call ToLookup instead of ToDictionaty.
After splitting the second time you create a CustomDictionary from the items in that array, then use ToList to make a list of the result.
List<CustomDictionary> keyVal =
val.Split(',')
.Select(x => x.Split('='))
.Select(a => new CustomDictionary(a[0], a[1]))
.ToList();
There is already a class in the framework having a key and value, which you can use instead:
List<KeyValuePair<string, string>> keyVal =
val.Split(',')
.Select(x => x.Split('='))
.Select(a => new KeyValuePair<string, string>(a[0], a[1]))
.ToList();
You can also use a Dictionary<string, string> instead of a list of key-value pairs. It stores the value based on the hash code of the key, so getting a value by key is much faster than looking through a list (but it doesn't retain the order of the items):
Dictionary<string, string> keyVal =
val.Split(',')
.Select(x => x.Split('='))
.ToDictionary(a => a[0], a => a[1]);
This is how you would do it:
var parts = theString.Split(',');
var myList = new List<CustomDictionary>();
foreach(string part in parts)
{
var kvp = part.Split('=');
myList.Add(new CustomDictionary(kvp[0], kvp[1]));
}
This can also be done using LINQ.
Since you have 2 OUs you can't use Dictionary. Instead use Lookup
string input = "AD=Demo,OU=WEB,OU=IT,L=MyCity,C=MyCountry";
var dict = Regex.Matches(input, #"(\w+)=([^,$]+)").Cast<Match>()
.ToLookup(m => m.Groups[1].Value, m => m.Groups[2].Value);
what about MyString.split(','); and the on each string you get:
CO.key = SubString.split('=')[0];
CO.value = SubString.split('=')[1];
With LINQ:
List<CustomDictionary> myList = (from x in input.Split(new char[] { ',' })
select
new CustomDictionary (x.Substring(0, x.IndexOf('=')), x.Substring(x.IndexOf('=') + 1))
).ToList();
string str = "AD=Demo,OU=WEB,OU=IT,L=MyCity,C=MyCountry";
var result = str.Split(',').Select(s =>
{
var tmp = s.Split('=');
return new CustomDictionary(tmp[0], tmp[1]);
}).ToList();
Related
I have a string like this:
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
What am I trying to achieve is this:
Comma separate values
After separating them, trim down '{' and '}' chars from start and end.
Store them in a dictionary.
Output should be like this:
a,b
c,d
e,f //etc..,
Have written this program below and it works perfectly fine.
The question is, Are there any short / perfect way of doing this ?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
var splitString = strings1.Split(',');
var splitList = splitString.ToList();
var output = new List<string>();
splitList.ForEach(x =>
{
output.Add(x.Trim());
});
splitList = new List<string>();
output.ForEach(x =>
{
splitList.Add(x.Trim());
});
var dict = new Dictionary<string, string>();
splitList.ForEach(x =>
{
var outpt = x.Split('=');
dict.Add(outpt[0], outpt[1]);
});
var dict1 = new Dictionary<string, string>();
foreach (var x in dict.Keys)
{
var val = dict[x];
var y = val.TrimStart('{').ToString().TrimEnd('}').ToString();
dict1.Add(x, y);
}
foreach(var y in dict1.Keys)
{
var stringFormatted = y + dict1[y];
Console.Write(stringFormatted);
Console.WriteLine();
}
}
}
Definitely. The following Linq code should give the same results.
var dictionary = yourString.Split(',')
.Select(x => x.Split('='))
.ToDictionary(x => x[0].Trim(), x => x[1].Trim('}','{',' '));
Note that like your code there is no error checking for entries that are missing the equal sign.
Very simple. Without LINQ, it would look like:
var strings1 = #"a={b},c={d},e={f},g={h},
i={j},k={l},m={n},o={p},q={r},s={t},u={v},w={x},
y={z}, alpha={beta}";
var splitString = strings1.Split(',');
var dict = new Dictionary<string, string>();
foreach (string s in splitString)
{
var splitPair = s.Split('=');
dict[splitPair[0].Trim()] = splitPair[1].Trim(' ', '{', '}');
}
I am trying to loop through two concurrent dictionaries like the code below, however I want to use a lambda expression instead
foreach (var s in sb_eventdata)
{
foreach (var f in final_data)
{
if (s.Value.Car.Equals(f.Value.Car))
{
Console.Writeline("Found!");
}
}
}
var values = sb_eventdata.Where(k => k.Value.Hometeam.Contains( ???? );
I'm really not sure what to pass into contains, I assume another lambda expression but what?
The closest linq expression to your loops would be:
var sb_eventdata = new Dictionary<string, string>{ {"a", "a"}, {"b", "b"}};
var final_data = new Dictionary<string, string>{{"a", "a"}, {"b", "b"}, {"c","c"}};
var result =
// first loop
sb_eventdata.Select(s =>
// second loop
final_data.Where(f => s.Value.Equals(f.Value)))
// flatten results (returns results from the first dictionary)
.SelectMany(x => x);
You can use a linq Intersect function to find like items in a list.
Then display all like items.
var foo = sb_eventdata.Select(o => o.Value.Car).Intersect(final_data.Select(o => o.Value.Car));
foreach (var item in foo)
{
Console.Writeline("Found!");
}
I think your friend is the Join() method.
In "LinqPad style":
void Main()
{
var a = new[] {
new Car("Opel",200),
new Car("Volkswagen",300),
new Car("Audi", 500)
};
var b = new[] {
new Car("Peugeot", 180),
new Car("Seat", 300),
new Car("Volvo", 480)
};
var c = a.Join(b, ak => ak.Value, bk => bk.Value, (ak,bk) => new {A=ak.Name,B=bk.Name,ak.Value});
c.Dump();
}
// Define other methods and classes here
class Car {
public string Name;
public int Value;
public Car (string name, int value) {
Name = name;
Value = value;
}
}
If you just want to know if both dictionary share at least one value, you can use Any:
if(sb_eventdata.Any(s =>
final_data.Any(f => s.Value.Car.Equals(f.Value.Car))))
Console.WriteLine("Found!");
or with Contains:
if(sb_eventdata.Any(s => final_data.ContainsValue(s.Value)))
Console.WriteLine("Found!");
and if you want to count how many of sb_eventdata are in final_data:
sb_eventdata.Where(s => final_data.ContainsValue(s.Value)).Count();
I am working on a small project but have run into a performance roadblock.
I have a Dictionary<string, string>()
I have a string[].
Lets say my Dictionary has 50,000 entries, and my string[] has 30,000 entries.
I want to collect the Keys from my Dictionary where the value.ToCharArray().OrderBy(x => x) equals a value.ToCharArray().OrderBy(x => x) of my string[].
I have tried reducing the number of KeyValue pairs I have to look through by comparing the length of my string[] value to the values in the Dictionary, but that has not really gained me any performance.
Does anyone have an ideas how I can improve the performance of this lookup?
Thanks!
To expand the pseudocode:
var stringToLookUp = GetSomeStrings(s.ToString()).Select(x => x).OrderBy(x => x).ToArray();
var aDictionaryOfStringString = GetDictionary(Resources.stringList);
var results = new List<string>();
foreach (var theString in stringToLookUp.Where(aString=> aString.Length > 0))
{
if (theString.Length > 0)
{
var theStringClosure = theString;
var filteredKeyValuePairs = aDictionaryOfStringString.Where(w => w.Value.Length == theStringClosure.Length && !results.Contains(w.Key)).ToArray();
var foundStrings = filteredKeyValuePairs.Where(kv => kv.Value.ToCharArray().OrderBy(c => c).ToArray().SequenceEqual(theStringClosure))
.Select(kv => kv.Key)
.ToArray();
if (foundStrings.Any()) results.AddRange(foundStrings);
}
}
I think principal problem is you iterate over whole dictionary in every single iteration - this is O(N^2). Better build hashset based on your modified key (either from dictionary or from array) and iterate over the second. This is O(N).
// some values
var dictionary = new Dictionary<string, string>();
var fields = new string[]{};
string[] modifiedFields = new string[fields.Length];
for(var i =0; i < fields.Length; i++)
{
modifiedFields[i] = new string(fields[i].ToCharArray().OrderBy(x =>x).ToArray());
}
var set = new HashSet<string>(modifiedFields);
var results = new List<string>();
foreach(var pair in dictionary)
{
string key = new string(pair.Value.ToCharArray().OrderBy(x =>x).ToArray());
if (set.Contains(key))
{
results.Add(pair.Key);
}
}
You can try this
var stringToLookUp = GetSomeStrings(s.ToString()).Select(x => x).OrderBy(x => x).ToArray();
var aDictionaryOfStringString = GetDictionary(Resources.stringList);
var results = aDictionaryOfStringString.Where(kvp => stringToLookUp.Select(s => s.OrderBy(x => x)).Contains(kvp.Value.OrderBy(x => x))).Select(kvp => kvp.Key).ToList();
If you are given an array with random prefixes, like this:
DOG_BOB
CAT_ROB
DOG_DANNY
MOUSE_MICKEY
DOG_STEVE
HORSE_NEIGH
CAT_RUDE
HORSE_BOO
MOUSE_STUPID
How would i go about sorting this so that i have 4 different arrays/lists of strings?
So the end result would give me 4 string ARRAYS or lists with
DOG_BOB,DOG_DANNY,DOG_STEVE <-- Array 1
HORSE_NEIGH, HORSE_BOO <-- Array 2
MOUSE_MICKEY, MOUSE_STUPID <-- Array 3
CAT_RUDE, CAT_ROB <-- Array 4
sorry about the names i just made them up lol
var fieldNames = typeof(animals).GetFields()
.Select(field => field.Name)
.ToList();
List<string> cats = new List<string>();
List<string> dogs = new List<string>();
List<string> mice= new List<string>();
List<string> horse = new List<string>();
foreach (var n in fieldNames)
{
var fieldValues = typeof(animals).GetField(n).GetValue(n);"
//Here's what i'm trying to do, with if statements
if (n.ToString().ToLower().Contains("horse"))
{
}
}
So i need them to be splitted into STRING ARRAYS/STRING LISTS and NOT just strings
string[] strings = new string[] {
"DOG_BOB",
"CAT_ROB",
"DOG_DANNY",
"MOUSE_MICKEY",
"DOG_STEVE",
"HORSE_NEIGH",
"CAT_RUDE",
"HORSE_BOO",
"MOUSE_STUPID"};
string[] results = strings.GroupBy(s => s.Split('_')[0])
.Select(g => String.Join(",",g))
.ToArray();
Or maybe something like this
List<List<string>> res = strings.ToLookup(s => s.Split('_')[0], s => s)
.Select(g => g.ToList())
.ToList();
var groups = fieldNames.GroupBy(n => n.Split('_')[0]);
Usage
foreach(var group in groups)
{
// group.Key (DOG, HORSE, CAT, etc)
foreach(var name in group)
// all names groped by prefix
}
foreach (String s in strings)
{
if (s.StartsWith("CAT_")
cats.Add(s);
else if (s.StartsWith("HORSE_")
horses.Add(s);
// ...
}
Or:
foreach (String s in strings)
{
String[] split = s.Split(new Char [] { '_' });
if (split[0].Equals("CAT")
cats.Add(s);
else if (split[0].Equals("HORSE")
horses.Add(s);
// ...
}
But I would prefer the first one.
Algorithmically, I'd do the following:
Parse out all unique prefixes by using the "_" as your delimeter.
Loop through your list of prefixes.
2a. Retrieve any values that have your prefix (loop/find/regex/depends on structure)
2b. Place retrieved values in a List.
2c. Sort list.
Output your results, or do what you need with your collections.
You can order the list up front and sort by prefix:
string[] input = new string[] {"DOG_BOB","CAT_ROB","DOG_DANNY","MOUSE_MICKEY","DOG_STEVE","HORSE_NEIGH","CAT_RUDE","HORSE_BOO","MOUSE_STUPID"};
string[] sortedInput = input.OrderBy(x => x).ToArray();
var distinctSortedPrefixes = sortedInput.Select(item => item.Split('_')[0]).Distinct().ToArray();
Dictionary<string, string[]> orderedByPrefix = new Dictionary<string, string[]>();
for (int prefixIndex = 0; prefixIndex < distinctSortedPrefixes.Length; prefixIndex++)
{
string prefix = distinctSortedPrefixes[prefixIndex];
var group = input.Where(item => item.StartsWith(prefix)).ToArray();
orderedByPrefix.Add(prefix, group);
}
With LINQ, using something like
names.GroupBy(s => s.Substring(0, s.IndexOf("_"))) // group by prefix
.Select(g => string.Join(",", g)) // join each group with commas
.ToList(); // take the results
See it in action (some extra .ToArray() calls included for .NET 3.0 compatibility)
This LINQ expression does what you want.
var result = data.GroupBy(data.Split('_')[0])
.Select(group => String.Join(", ", group))
.ToList();
For a list of lists of strings use this expression.
var result = data.GroupBy(data.Split('_')[0])
.Select(group => group.ToList())
.ToList();
I have an array for example("1:2","5:90","7:12",1:70,"29:60") Wherein ID and Qty are separated by a ':' (colon), what I want to do is when there's a duplicate of IDs the program will add the qty and return the new set of arrays so in the example it will become ("1:72","5:90","7:12","29:60").
Ex.2 ("1:2","5:90","7:12","1:70","29:60","1:5") becomes ("1:77","5:90","7:12","29:60").
I want to solve it without using linq.
var foo = array.Select(s => s.Split(':'))
.GroupBy(x => x[0])
.Select(g =>
String.Format(
"{0}:{1}",
g.Key,
g.Sum(x => Int32.Parse(x[1]))
)
)
.ToArray();
Note, it's not necessary to parse the "keys," only the values.
Without LINQ:
var dictionary = new Dictionary<string, int>();
foreach (var group in array) {
var fields = group.Split(':');
if (!dictionary.ContainsKey(fields[0])) {
dictionary.Add(fields[0], 0);
}
dictionary[fields[0]] += Int32.Parse(fields[1]);
}
string[] foo = new string[dictionary.Count];
int index = 0;
foreach (var kvp in dictionary) {
foo[index++] = String.Format("{0}:{1}", kvp.Key, kvp.Value);
}
You have to do this manually. Loop through each list, check the ID for each element. Put it in a Dictionary<int, int>, Dictionary<id, qt>. If the dictionary contains the id, add it to the value.
Loop, add, check using Dictionary class.
If you want it without LINQ...
var totalQuantities = new Dictionary<int, int>();
foreach(var raw in sourceArr) {
var splitted = raw.Split(':');
int id = int.Parse(splitted[0]);
int qty = int.Parse(splitted[1]);
if(!totalQuantities.ContainsKey(id)) {
totalQuantities[id] = 0;
}
totalQuantities[id] += qty;
}
var result = new string[totalQuantities.Count];
int i=0;
foreach(var kvp in totalQuantities) {
result[i] = string.Format("{0}:{1}", kvp.Key, kvp.Value);
i++;
}
(
from raw in arr
let splitted = raw.Split(':')
let id = int.Parse(splitted[0])
let qty = int.Parse(splitted[1])
let data = new { id, qty }
group data by data.id into grp
let totalQty = grp.Sum(val => val.qty)
let newStr = string.Format("{0}:{1}", grp.Key, totalQty
select newStr
)
.ToArray()
Note that the code may contain accidental errors, as it was written in notepad.
var input=new string[]{"1:2","5:90","7:12","1:70","29:60","1:5"};
var result=input
.Select(s=>s.Split(':'))
.Select(x=>x.Select(s=>int.Parse(s)).ToArray())
.GroupBy(x=>x[0])
.Select(g=>g.Key+":"+g.Sum(x=>x[1]));
I was too lazy to specify the culture everywhere. You probably want to do that before putting it into production, or it will fail for cultures with unusual integer representations.
var totals=new Dictionary<int,int>
foreach(string s in input)
{
string[] parts=s.Split(':');
int id=int.Parse(parts[0]);
int quantity=int.Parse(parts[0]);
int totalQuantity;
if(!totals.TryGetValue(id,out totalQuantity))
totalQuantity=0;//Yes I know this is redundant
totalQuanity+=quantity;
totals[id]=totalQuantity;
}
var result=new List<string>();
foreach(var pair in totals)
{
result.Add(pair.Key+":"+pair.Value);
}
try this:
List<string> items = new List<string>(new string[] { "1:2", "5:90", "7:12", "1:70", "29:60" });
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (string item in items)
{
string[] data = item.Split(':');
string key = data[0];
if (!dictionary.ContainsKey(data[0]))
{
int value = dictionary[data[0]];
dictionary[key] += int.Parse(data[1]);
}
}
//Used dictionary values here