Sorting a string based on prefixes - c#

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();

Related

Loop through a List<string> but only take a part of each string inside

I am wondering if anyone can help me, I am trying to loop through a list of strings but only take the part to the left of ":" but not including the ":" I can do this with the approach below but I am trying to implement this by using Linq instead. Any help would be greatly appreciated.
List<string> Results = new List<string>();
List<string> strings = new List<string>
{
"121:sdfdsfds",
"122:sdfdsfds",
"123:sdfdsfds"
};
for (var i = 0; i < strings.Count; i++)
{
string[] tokens = strings[i].Split(':');
if (tokens.Any())
{
Results.Add(tokens[0]);
}
}
Use the Select method (System.Linq namespace)
class Program
{
static void Main(string[] args)
{
List<string> strings = new List<string>
{
"121:sdfdsfds",
"122:sdfdsfds",
"123:sdfdsfds"
};
List<string> Results = strings
.Select(s => s.Split(':')[0])
.ToList();
Results.ForEach(s => Console.WriteLine(s));
Console.ReadKey();
}
}
Output:
121
122
123
Method chain syntax:
List<string> Results = strings.Select(t => t.Split(':'))
.Where(tokens => tokens.Any())
.Select(tokens => tokens[0]).ToList();
Query syntax:
List<string> Results = (from t in strings
select t.Split(':')
into tokens
where tokens.Any()
select tokens[0]).ToList();
List<string> Results = strings
.Select(item => item.Split(':').FirstOrDefault())
.Where(item => item != null).ToList();
You can take each item of the string array, split it, and return index[0] all inside a select statement:
var results = strings.Select(i => i.Split(':')[0]).ToList();
If there's a chance that some items will be empty and you don't want to include them, you can use this syntax on the string.Split method:
var results = strings
.Select(i => i.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries)
.FirstOrDefault())
.Where(i => i != null)
.ToList();
Use forEach,
strings.ForEach(x => Results.Add(x.Split(':')[0]));

Splitting text and converting linq

I have a string array and want to convert it to double array with LINQ. I don't want to use foreach loops.
var texts = new List<string>
{"-87.98 65", "-86.98 75", "-97.98 78", "-81.98 65"}
To:
var numerics = new List<IEnumerable<double>>
{
new List<double>{-87.98, 65},
new List<double>{86.98, 75},
new List<double>{-97.98 78},
new List<double>{-81.98 65}
}
Is there any short way with LINQ?
You could use this:
var doubles = texts.Select(x => x.Split()
.Select(y => double.Parse(y, CultureInfo.InvariantCulture))
.ToList()
.AsEnumerable() // added to comply to the desired signature
)
.ToList() // added to comply to the desired signature
;
It first selects the string, splits it on spaces, and then parses the strings in the string array to doubles. That output is converted to a list.
You can do something like this:
var texts = new List<string> { "-87.98 65", "-86.98 75", "-97.98 78", "-81.98 65" };
List<List<double>> newList =
texts.Select(t => t.Split(' ').Select(s => Convert.ToDouble(s)).ToList()).ToList();
foreach (var item in newList)
foreach (var item2 in item)
Console.Write(item2 + " ;");
Output : -87,98; 65; -86,98; 75; -97,98; 78; -81,98; 65;
But i wouldn't call it 'a short way'...
This fits the signature:
var texts = new List<string> {"-87.98 65", "-86.98 75", "-97.98 78", "-81.98 65"};
List<IEnumerable<double>> numerics =
texts.Select(s => new List<double>(s.Split().Select(sub => Double.Parse(sub, CultureInfo.InvariantCulture))))
.Cast<IEnumerable<double>>()
.ToList();

Split string into custom List<T>

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();

How to get count similar word in list?

I have C# list with lot of similar name i want to count all individual similar word.
Example
Suppose list has these values
one,one,one,two,two,four,four,four
then i want to calculate like this
one 3
two 2
four 3
how can i calculate value like this from list.
I would split the string on comma, loop through all the results and add each word to a hashtable or dictionary with a value of one. If the word (key) is already present, then increment the value.
string[] values = "one,one,one,two,two,four,four,four".Split(',');
var counts = new Dictionary<string, int>();
foreach (string value in values) {
if (counts.ContainsKey(value))
counts[value] = counts[value] + 1;
else
counts.Add(value, 1);
}
Or, if you prefer, here is a LINQ solution
var counts = values.GroupBy<string, string, int>(k => k, e => 1)
.Select(f => new KeyValuePair<string, int>(f.Key, f.Sum()))
.ToDictionary(k => k.Key, e => e.Value);
Here is a solution based on Linq:
string s = "one,one,one,two,two,four,four,four";
List<string> list = s.Split(',').ToList();
Dictionary<string, int> dictionary = list.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());
foreach (var kvp in dictionary)
Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
Output:
one: 3
two: 2
four: 3
This solutions doesn't take advantage of the fact that the common values are consecutive. If this is always the case, a slightly faster solution could be written, but this is fine for short lists, or if the items can come in any order.
Dictionaty<string, int> listCount = new Dictionaty<string, int>();
for (int i = 0; i < yourList.Count; i++)
{
if(listCount.ContainsKey(yourList[i]))
listCount[yourList[i].Trim()] = listCount[yourList[i].Trim()] + 1;
else
listCount[yourList[i].Trim()] = 1;
}
For List, you could do the following (untested):
List<string> list = new List<string>()
{
"One",
"One",
"Two",
// etc
}
Dictionary<string, int> d = new Dictionary<string, int>();
foreach (string s in list)
{
if (d.ContainsKey(s))
d.Add(s, 1);
else
d[s]++;
}
The preferred (and cleaner) method is to do this using GroupBy and Count with Linq, but I don't have the type to type out the syntax at the moment.
Good luck!

an array question

i have an array below
string stringArray = new stringArray[12];
stringArray[0] = "0,1";
stringArray[1] = "1,3";
stringArray[2] = "1,4";
stringArray[3] = "2,1";
stringArray[4] = "2,4";
stringArray[5] = "3,7";
stringArray[6] = "4,3";
stringArray[7] = "4,2";
stringArray[8] = "4,8";
stringArray[9] = "5,5";
stringArray[10] = "5,6";
stringArray[11] = "6,2";
i need to transform like below
List<List<string>> listStringArray = new List<List<string>>();
listStringArray[["1"],["3","4"],["1","4"],["7"],["3","2","8"],["5","6"],["2"]];
how is that possible?
I think what you actually want is probably this:
var indexGroups = x.Select(s => s.Split(',')).GroupBy(s => s[0], s => s[1]);
This will return the elements as a grouped enumeration.
To return a list of lists, which is what you literally asked for, then try:
var lists = x.Select(s => s.Split(',')).GroupBy(s => s[0], s => s[1])
.Select(g => g.ToList()).ToList();
There's no shorthand like that. You'll have to break into a loop and split each array and add to the list.
Non LINQ version (I must admit its much uglier, but you may have no choice)
var index = new Dictionary<string, List<string>>();
foreach (var str in stringArray) {
string[] split = str.Split(',');
List<string> items;
if (!index.TryGetValue(split[0], out items)) {
items = new List<string>();
index[split[0]] = items;
}
items.Add(split[1]);
}
var transformed = new List<List<string>>();
foreach (List<string> list in index.Values) {
transformed.Add(list);
}

Categories

Resources