Cut last character from string which was earlier splitted by char - c#

I want to order list with string names by name included in brackes.
List<string> result = new List<string>();
list.ForEach(elem => result.Add(elem.Value));
result.Add(item);
result = result.OrderBy(o=>o.Split(';')[0].Substring(0, o.Length - 1).Split('(')[1]).ToList();
Example: 2-osobowy(Agrawka);Śniadanie+Obiadokolacja
I want to extract this name Agrawka
How to change instruction Substring(0, o.Length - 1)to cut last char from splitted string in orderby instruction?

If I right understood you want extract values in the brackets and sort input' list by that values. So code below sorts your data and extracts value to additional list:
List<string> resultList = new List<string>() { "2-osobowy(Bgrawka);Śniadanie+Obiadokolacja", "2-osobowy(Agrawka);Śniadanie+Obiadokolacja" };
string tempStr = null;
var extractedStr = new List<String>();
resultList = resultList.OrderBy(o =>
{
var extract = (tempStr = o.Split(';')[0].Split('(')[1]).Substring(0, tempStr.Length - 1);
extractedStr.Add(extract);
return extract;
}).ToList();
If you want only sort input data just simplify the lambda:
resultList = resultList.OrderBy(o => (tempStr = o.Split(';')[0].Split('(')[1]).Substring(0, tempStr.Length - 1)).ToList();

Related

Searching for a pattern

I need to search a list for some pattern is present or not.
var result=roles.Where(z=>z.Contains(x) && z.Contains(y)).ToList();
string x = "Resource:resource1:resource2";
string y = "writer";
List<string> roles=new List<string>{"Resource::reader","Resource:resource1::Deleter","Resource:resource1::writer"};
I need to find if any value is present in roles list like:
Resource::writer or Resource:resource1::writer or
Resource:resource1:resource2::writer
i.e Split x based on : and append y to the combination of splitted x
If my understanding of your problem is right :
You have a list which can contain anything that you names roles. Thoses roles are in format A::B or A:B::C or A:B:C::D etc...
And what you want to achieve is to find if any "path" or combination of path from x can give the role y ?
for instance : if you have roles like A::Z A::Y A:B::X A:B:C::X
you have x which is A:B:C
and you have y which is X
you want to check is you have A::X in the list
if you don't, you're gonna check A:B::X in the list,
and if you still don't, you will look for A:B:C::X
So again if I'm right, you could consider something like this :
String path = "A:B:C";
String roleNeeded = "X";
List<String> roles = new List<string>() { "A::Z", "A::Y", "A:B::X" };
List<String> pathStep = new List<string>();
pathStep = path.Split(':').ToList();
String lookupPath = String.Empty;
String result = String.Empty;
pathStep.ForEach( s =>
{
lookupPath += s;
if (roles.Contains(lookupPath + "::" + roleNeeded))
{
result = lookupPath + "::" + roleNeeded;
}
lookupPath += ":";
});
if (result != String.Empty)
{
// result is Good_Path::Role
}
This way you start spliting your path X as a list and you aggregate it in the foreach to look at each step.
You should consider using Regular Expression. Try this out,
string x = "Resource:resource1:resource2";
string y = "writer";
List<string> roles;
List<string> words = new List<string> { x, y };
// We are using escape to search for multiple strings.
string pattern = string.Join("|", words.Select(w => Regex.Escape(w)));
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
// You got matched results...
List<string> matchedResults = roles.Where(regex.IsMatch).ToList();
string x = "Resource:resource1:resource2";
string y = "writer";
List<string> roles = new List<string>
{
"Resource::writer",
"Resource:resource1:resource2::writer"
};
var records = x.Split(':').Select((word, index) => new { word, index });
var result =
from record in records
let words = $"{string.Join(":", records.Take(record.index + 1).Select(r => r.word))}::{y}"
join role in roles on words equals role
select words;

Finding number of instances of exact word of "x" in text

I'm working c# to find out number of instances of exact word of "x".
For example:
List<string> words = new List<string> {"Mode", "Model", "Model:"};
Text= "This is Model: x Type: y aa: e";
I've used Regex:
for(i=0; i<words.count; i++)
{
word= list[i]
int count= Regex.Matches(Text,word)
}
But its not working. The result of above code gave count=1 for every Mode, Model, and Model:.
I want to have my count to be 0 for Mode, 0 for Model, but 1 for Model: that it finds the number of instance of exact word.
Forgot that I can't use split in my case. Is there any way I can get not using split?
I use LINQ for this purpose:
List<string> words = new List<string> { "Mode", "Model", "Model:" };
Text = "This is Model: x Type: Model: y aa: Mode e Model:";
var textArray = Text.Split(' ');
var countt = words.Select(item => textArray.ToList().Contains(item) ?
textArray.Count(d => d == item) : 0).ToArray();
Result:
For Mode => count = 1
For Model => count = 0
For Model: => count = 3
EDIT: I prefer to use LINQ for this purpose because as you see it is more easier and cleaner in this scenario, but if you are looking for a Regex solution yet you could try this:
List<int> count = new List<int>();
foreach (var word in words)
{
var regex = new Regex(string.Format(#"\b{0}(\s|$)", word), RegexOptions.IgnoreCase);
count.Add(regex.Matches(Text).Count);
}
EDIT2: Or by combining LINQ and Regex and without Split you can:
List<int> count = words.Select(word => new Regex(string.Format(#"\b{0}(\s|$)", word), RegexOptions.IgnoreCase))
.Select(regex => regex.Matches(Text).Count).ToList();
Although #S.Akhbari 's solution works... I think using Linq is cleaner:
var splitted = Text.Split(' ');
var items = words.Select(x => new { Word = x, Count = splitted.Count(y => y == x) });
Each item will have Word and Count properties.
See it in action here
\b matches on word boundaries.
for(i=0; i<words.count; i++)
{
word= list[i]
var regex = new Regex(string.Format(#"\b{0}\b", word),
RegexOptions.IgnoreCase);
int count= regex.Matches(Text).Count;
}

Sort a List<string> comparing with a string

I need to sort a List<string> by comparing the list with a string
for example:
I have a List that contains the following Items.
Kaboki
kriiki
Kale
Kutta
Kiki
Kicki
Krishna
Kseaki
The search keyword is ki I need to sort the list items using the keyword in such a way that, the strings that match in the string start have should be first and the string having the matched string in the other position have to be in the last
Here is my current code
public static List<string> GetLocations(string prefixText)
{
try
{
DataTable dtlocs = (DataTable) HttpContext.Current.Session["locations"];
var dValue = from row in dtlocs.AsEnumerable()
where row.Field<string>("Location_Name").ToLower().Contains(prefixText.ToLower())
select row.Field<string>("Location_Name");
var results = dValue.OrderBy(s => s.IndexOf(prefixText, StringComparison.Ordinal));
var str = new List<string>(results.ToList());
if (!str.Any())
str.Add("No locations found");
return str;
}
catch (Exception)
{
var str = new List<string> {"No locations found"};
return str;
}
}
Here I'm able to get the first matched values to the top but cannot sort the remaining values
and I have another issue. there is a word King Koti and i'm searhing for Ko and this word comes to first.I think this happens because, the string has two sub strings and one of the substrings start with the matched word.
and can I make the matched letters to bold ??
var res = list.OrderBy(y=> !y.StartsWith("Ki", StringComparison.OrdinalIgnoreCase))
.ThenBy(x => x)
OrderBy orders false before true:
var result = list.OrderBy(s => !s.StartsWith("ki", StringComparison.OrdinalIgnoreCase))
.ThenBy(s => !s.ToLower().Contains("ki"));
I think this should work:
list = (from str in list
let idx = str.IndexOf(keyword, StringComparison.OrdinalIgnoreCase)
let change = idx != 0 ? idx : int.MinValue
orderby change
select str).ToList();
You can use a combination of Linq's OrderBy and the IndexOf methods:
var input = ...
var search = "ki";
var results = input.Select(Value => new { Value, Index = s.IndexOf(search, StringComparison.InvariantCultureIgnoreCase) })
.Where(pair => pair.Index >= 0)
.OrderBy(pair => pair.Index)
.Select(pair => pair.Value);
Or in query syntax:
var results =
from s in input
let i = s.IndexOf(search, StringComparison.InvariantCultureIgnoreCase)
where i >= 0
orderby i
select s;

C# Get substring with specific pattern from string

I have a list of strings like this:
List<string> list = new List<string>();
list.Add("Item 1: #item1#");
list.Add("Item 2: #item2#");
list.Add("Item 3: #item3#");
How can I get and add the substrings #item1#, #item2# etc into a new list?
I am only able to get the complete string if it contains a "#" by doing this:
foreach (var item in list)
{
if(item.Contains("#"))
{
//Add item to new list
}
}
You could have a look at Regex.Match. If you know a little bit about regular expressions (in your case it would be a quite simple pattern: "#[^#]+#"), you can use it to extract all items starting and ending with '#' with any number of other characters other than '#' in between.
Example:
Match match = Regex.Match("Item 3: #item3#", "#[^#]+#");
if (match.Success) {
Console.WriteLine(match.Captures[0].Value); // Will output "#item3#"
}
Here's another way using a regex with LINQ. (Not sure your exact requirements reference the regex, so now you may have two problems.)
var list = new List<string> ()
{
"Item 1: #item1#",
"Item 2: #item2#",
"Item 3: #item3#",
"Item 4: #item4#",
"Item 5: #item5#",
};
var pattern = #"#[A-za-z0-9]*#";
list.Select (x => Regex.Match (x, pattern))
.Where (x => x.Success)
.Select (x => x.Value)
.ToList ()
.ForEach (Console.WriteLine);
Output:
#item1#
#item2#
#item3#
#item4#
#item5#
LINQ would do the job nicely:
var newList = list.Select(s => '#' + s.Split('#')[1] + '#').ToList();
Or if you prefer query expressions:
var newList = (from s in list
select '#' + s.Split('#')[1] + '#').ToList();
Alternatively, you can use regular expressions as suggested with Botz3000 and combine those with LINQ:
var newList = new List(
from match in list.Select(s => Regex.Match(s, "#[^#]+#"))
where match.Success
select match.Captures[0].Value
);
The code will solve your problem.
But if the string does not contain #item# then the original string will be used.
var inputList = new List<string>
{
"Item 1: #item1#",
"Item 2: #item2#",
"Item 3: #item3#",
"Item 4: item4"
};
var outputList = inputList
.Select(item =>
{
int startPos = item.IndexOf('#');
if (startPos < 0)
return item;
int endPos = item.IndexOf('#', startPos + 1);
if (endPos < 0)
return item;
return item.Substring(startPos, endPos - startPos + 1);
})
.ToList();
How about this:
List<string> substring_list = new List<string>();
foreach (string item in list)
{
int first = item.IndexOf("#");
int second = item.IndexOf("#", first);
substring_list.Add(item.Substring(first, second - first);
}
You could do that by simply using:
List<string> list2 = new List<string>();
list.ForEach(x => list2.Add(x.Substring(x.IndexOf("#"), x.Length - x.IndexOf("#"))));
try this.
var itemList = new List<string>();
foreach(var text in list){
string item = text.Split(':')[1];
itemList.Add(item);
}

Sorting a string based on prefixes

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

Categories

Resources