C# How can I do a string replace method on the collection? - c#

I have the following method which return a collection so I can then build a dropdown menu from in MVC. The problem is, I want to replace a substring within the values in the collection but I am not sure how to do so in C# (I'm a classic vb guy).
public class RolesManagement
{
public static IEnumerable<string> BuildRoles(string DesiredRole)
{
var UserRoles = Roles.GetAllRoles();
IEnumerable<string> roles;
roles = UserRoles.Where(x => x.Contains("Sub")).Except(rejectAdmin);
return roles;
}
}
The above has been simplified for brevity. Each role in the roles collection looks like this:
SubUser
SubAdmin
SubManager.
I simply want to return
User
Admin
Manager
What would be the best approach for this in C# please?
My guess is that I have to do a foreach and replace the substring on each loop and the re-populate the value before moving to the next item.
If you could provide a code sample that would be great as I seem to still me tripping over syntax issues.
Much appreciated!

You could do that with LINQ.
roles = UserRoles
.Where(x => x.Contains("Sub"))
.Except(rejectAdmin)
.Select(x => x.Replace("Sub", ""));
Edit: Note that this method simply replaces all occurrences of the string "Sub" in all of the strings in roles. It's a very broad stroke and you may need to use a different lambda function if you only want to do the replacements you mentioned. See Romoku's post for help with that.

I would say if the roles are not going to change very often then make a mapping Dictionary.
public class RolesManagement
{
private static readonly Dictionary<string,string> RoleMapping =
new Dictionary<string,string>
{
{"SubUser", "User" },
{"SubManager", "Manager" },
{"SubAdmin", "Admin" }
};
public static IEnumerable<string> BuildRoles(string DesiredRole)
{
var UserRoles = Roles.GetAllRoles();
IEnumerable<string> roles;
roles = UserRoles.Where(x => x.Contains("Sub")).Except(rejectAdmin);
return roles.Select(r => RoleMapping.ContainsKey(r) ? RoleMapping[r] : r);
}
}
Or just store them inside the database as a FriendlyName column.

this will return all items start with sub, with the sub removed
IEnumerable<string> = UserRoles
.Where(x => x.StartsWith("sub"))
.Select(y => y.Remove(0,3));

public static IEnumerable<string> GetCorrectedRoleNames(IEnumerable<string> roles)
{
List<string> correctedRoles = new List<string>();
foreach (string role in roles)
correctedRoles.Add(Regex.Replace(role, "Sub", string.Empty));
return correctedRoles.AsEnumerable();
}

public static IEnumerable<string> BuildRoles(string DesiredRole)
{
var UserRoles = Roles.GetAllRoles();
IEnumerable<string> roles;
roles = UserRoles.Where(x => x.Contains("Sub")).Except(rejectAdmin).Select(x=>x.Replace("Sub","");
return roles;
}
i supposed that x is string variable if not you have to do this replace on string collection

If I understand your problem right, you need to remove the occurence of "Sub" in a string. You can do additional checks if you have other conditions , like "Sub" is at the beginning of the string, case-insensitivity, etc.
One of the ways is to find the index of the string to be removed and then remove.
var s = "SubUser";
var t = s.Remove(s.IndexOf("Sub"), "Sub".Length);
Alternatively, you can also replace the string to be removed with an empty string.
var t = s.Replace("Sub", "");
Hope that helps.

Try this
List<string> x = new List<string>();
x.Add("SubUser");
x.Add("SubAdmin");
x.Add("SubManager");
var m = x.Select( y => y.Replace("Sub", ""));

Related

How to get the entire list instead of only the first result? Net Core 3.1

The following functions return only the first row of the database, would you please guide me get the entire rows please?
My Function :
private List<Phrases_Clp> PhrasesStringToListPhrases_Clp(string phrases_codes)
{
List<Phrases_Clp> phrases_Clps = new List<Phrases_Clp>();
if (!String.IsNullOrEmpty(phrases_codes))
{
if (phrases_codes.Contains(","))
{
string[] listprhases = phrases_codes.Split(",");
foreach (var item in listprhases)
{
var mentiontoinsert = _context.Phrases_Clps.FirstOrDefault(m =>
m.Phrase_Numero == item);
phrases_Clps.Add(mentiontoinsert);
}
}
else
{
var mentiontoinsert = _context.Phrases_Clps.FirstOrDefault(m =>
m.Phrase_Numero == phrases_codes);
phrases_Clps.Add(mentiontoinsert);
}
}
return phrases_Clps;
}
UPDATE :
It still gives me the first result. I wonder if I should do changes in my view as I display information from another table which correspond the cell values in the current table.
Table Identification_Produit
Table Phrases Clp
Current Output:
Desired Output is to display 'Mentions Dangers' of each Product.
GET:
//GET: EvaluationRisque/Create
[Authorize(Roles = "Administrateur, Modificateur")]
public async Task<IActionResult> Create()
{
List<Models.dbo.equipements_protection.Equipement_Protection> listsequipement = _context.Equipement_Protections.ToList();
Create_Viewbags();
var model = new EvaluationRisquesViewModel();
var produitUtiliseByProduitId = await _context.Identification_Produit.FirstOrDefaultAsync();
model.MentionsDanger = produitUtiliseByProduitId;
model.List_Mentions_Danger = PhrasesStringToListPhrases_Clp(model.MentionsDanger.Mentions_Danger);
return View(model);
}
Bootstrap Model in the View Page:
<td>#foreach (var mention_danger in Model.List_Mentions_Danger)
{
<p> #mention_danger.Phrase_Numero : #mention_danger.Phrase_Libelle
</p>}
</td>
Change FirstOrDefault(...) to .Where(...).ToList() (or use phrases_Clps.AddRange( _context.Phrases_Clps.Where(...))).
But actually there is no need to make multiple requests to the database and you can skip conditional splitting, so something like following should work:
List<Phrases_Clp> phrases_Clps = null;
if (!string.IsNullOrEmpty(phrases_codes))
{
string[] listprhases = phrases_codes.Split(","); // will be array with one item if there are no commas in string
phrases_Clps = _context.Phrases_Clps
.Where(m => listprhases.Contains(m.Phrase_Numero))
.ToList();
}
return phrases_Clps ?? new List<Phrases_Clp>();
Because you are using FirstOrDefault function in this line:
var mentiontoinsert = _context.Phrases_Clps.FirstOrDefault(m => m.Phrase_Numero == item);
replace it with Where function.
Thinking that to utilize the query as IQueryable.
Updated:
Thanks for #GuruStron (Guru/Sensei)'s opinion and for pointing out the issue from my previous answer.
In short,
Exit the function with an empty List if phrases_codes is an empty string or null.
Working with IQueryable to prepare the different search criteria and defer the execution.
Once the query is prepared, execute the query via .ToList().
if (String.IsNullOrEmpty(phrases_codes))
return new List<Phrases_Clp>();
IQueryable<Phrases_Clp> query = _context.Phrases_Clps;
if (phrases_codes.Contains(","))
{
string[] listprhases = phrases_codes.Split(",");
query = query
.Where(x => listprhases.Contains(x.Phrase_Numero));
}
else
{
query = query
.Where(x => x.Phrase_Numero == phrases_codes);
}
return query.ToList();
This is my minimalist proposal
private List<Phrases_Clp> PhrasesStringToListPhrases_Clp(string phrases_codes)
{
var listprhases = phrases_codes != null ? phrases_codes.Split(",") : new string[0];
return _context.Phrases_Clps.Where(x => listprhases.Contains(x.Phrase_Numero)).ToList();
}

How to remove duplicates from the list in C#

Please help me to fix this issue. My dropdown list looks something like this mentioned below.
Client
Contractor,Contractor,Contractor,Manager
Contractor,Manager
Manager
Operator
Viewer
I want to remove the duplicates and my output should be like :
Client
Contractor
Manager
Operator
Viewer
This is my code mentioned below:
Property:
public List<string> TeamRoleNames => TeamRoleUids.Select(MainRoles.GetRoleName).ToList();
Display Method:
{
result += " ; TeamRoleNames=" + this.TeamRoleNames;
}
GetRole Method:
{
string roleName;
if (RoleNameByUid.TryGetValue(roleUid, out roleName))
{
return roleName;
}
return null;
}
I have tried with Distinct Method mentioned below, But did not work like the output what I wanted!
public List<string> TeamRoleNames => TeamRoleUids.Select(MainRoles.GetRoleName).Distinct().ToList();
How can I fix this? Can anyone help?
Having elements comma separated require you to split them first to have an homogenous collection then do the distinct
// get the comma separated values out as 1 value each
// for that you can use split, remove empty and select many
// which will return as a single level list (flat)
var result = TeamRoleUids.SelectMany(o => o.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)).Distinct().ToList();
Consider converting the list to a set (hashset) since sets as a data structure doesn't allow duplicates.
More about hashsets form official documentation.
So, the solution would be similar to the following:
var hashSet = new HashSet<YourType>(yourList);
example:
var hashSet = new HashSet<string>(TeamRoleUids);
then converting it back toList() will remove duplicates.
If you have already tried Distinct and it hasn't worked, then you could do the following;
Split your string list to a List<string>
List<string> result = TeamRoleNames.Split(',').ToList();
Then when you're adding them to the dropdwon, check to see if the role is already in the dropdown. If so, move on, else add to the dropdown.
So something like
foreach(var role in this.TeamRoleNames)
{
if(!result.contains(role))
result += " ; TeamRoleNames=" + role;
}
You can use SelectMany to flatten a enumeration containing a nested enumeration. Here, we create the nested enumeration by splitting the string at the commas:
string[] input = {
"Client",
"Contractor,Contractor,Contractor,Manager",
"Contractor,Manager",
"Manager",
"Operator",
"Viewer"
};
var roles = input
.SelectMany(r => r.Split(','))
.Distinct()
.OrderBy(r => r)
.ToList();
foreach (string role in roles) {
Console.WriteLine(role);
}
prints
Client
Contractor
Manager
Operator
Viewer

How to combine two c# objects using Linq

I am trying to combine two LIKE objects together and remove duplicates.
Tried this
This didn't work
Here is my object [simple]
public class LabelItem
{
public string LabelName { get; set; }
public string LabelValue { get; set; }
}
my data call returns the same object type
public static List<LabelItem> ReturnControlLabelList(Enums.LanguageType languageType, string labelList = "")
I pass this to the method
string[] LABELLIST = new string[] { "foxLabel", "commonLabel" };
var helper = new LabelHelper(, LABELLIST);
this is where I get null
public LabelHelper(Enums.LanguageType languageType, string[] labelListName)
{
if (labelListName != null)
{
List<LabelItem> labels = new List<LabelItem>();
this.LabelList = new List<LabelItem>();
foreach (var name in labelListName)
{
labels = DBCommon.ReturnControlLabelList(languageType, name);
this.LabelList.Concat(labels).Distinct().ToList();
}
}
else
{
this.LabelList = null;
}
}
public List<LabelItem> LabelList { get; private set; }
The concat is not working. I keep getting count 0 for labels and I can see the returns come back with 275 and 125 in the for loop.
Thanks in advance for the help.
Still having an issue
I want to use the suggestion from below but am still struggling.
The string[] passed in will get two lists of labelitems that are not unique when joined together in the loop. I need the distinct of the multiple lists returned in this.LabelList.
I got it to work with this but...I'm sure it's crazy inefficient.
Thanks for the help.
this.LabelList = new List<LabelItem>();
foreach (var name in labelListName)
{
var ret = DBCommon.ReturnControlLabelList(languageType, name);
this.LabelList = this.LabelList.Concat(ret).Distinct().ToList();
}
var distinctList = this.LabelList.GroupBy(x => new { x.LabelName, x.LabelValue })
.Select(x => x.FirstOrDefault());
this.LabelList = new List<LabelItem>();
foreach (var item in distinctList)
{
this.LabelList.Add(item);
Debug.WriteLine(item.LabelName + ' ' + item.LabelValue);
}
}
this.LabelList.Concat(labels).Distinct().ToList(); without assigning it to something doesn't make much sense. LINQ query does not modify the source collection, it returns a new one, so you'd have to assign it back to this.LabelList if you want it to get updated:
this.LabelList = this.LabelList.Concat(labels).Distinct().ToList();
You should be aware, that it's highly inefficient solution, and you should go with something based on SelectMany:
this.LabelList
= labelListName.SelectMany(name => DBCommon.ReturnControlLabelList(languageType, name)
.Distinct()
.ToList();
Concat and most other linq methods return an IEnumerable which you then need to do something with. It will not change your existing list so you need to just assign it with:
this.LabelList = this.LabelList.Concat(labels).Distinct().ToList();

Comparing two strings with different orders

I have a dictionary with a list of strings that each look something like:
"beginning|middle|middle2|end"
Now what I wanted was to do this:
List<string> stringsWithPipes = new List<string>();
stringWithPipes.Add("beginning|middle|middle2|end");
...
if(stringWithPipes.Contains("beginning|middle|middle2|end")
{
return true;
}
problem is, the string i'm comparing it against is built slightly different so it ends up being more like:
if(stringWithPipes.Contains(beginning|middle2|middle||end)
{
return true;
}
and obviously this ends up being false. However, I want to consider it true, since its only the order that is different.
What can I do?
You can split your string on | and then split the string to be compared, and then use Enumerable.Except along with Enumerable.Any like
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
stringsWithPipes.Add("beginning|middle|middle3|end");
stringsWithPipes.Add("beginning|middle2|middle|end");
var array = stringsWithPipes.Select(r => r.Split('|')).ToArray();
string str = "beginning|middle2|middle|end";
var compareArray = str.Split('|');
foreach (var subArray in array)
{
if (!subArray.Except(compareArray).Any())
{
//Exists
Console.WriteLine("Item exists");
break;
}
}
This can surely be optimized, but the above is one way to do it.
Try this instead::
if(stringWithPipes.Any(P => P.split('|')
.All(K => "beginning|middle2|middle|end".split('|')
.contains(K)))
Hope this will help !!
You need to split on a delimeter:
var searchString = "beginning|middle|middle2|end";
var searchList = searchString.Split('|');
var stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
...
return stringsWithPipes.Select(x => x.Split('|')).Any(x => Match(searchList,x));
Then you can implement match in multiple ways
First up must contain all the search phrases but could include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x));
}
Or must be all the search phrases cannot include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x)) && search.Length == match.Length;
}
That should work.
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
string[] stringToVerifyWith = "beginning|middle2|middle||end".Split(new[] { '|' },
StringSplitOptions.RemoveEmptyEntries);
if (stringsWithPipes.Any(s => !s.Split('|').Except(stringToVerifyWith).Any()))
{
return true;
}
The Split will remove any empty entries created by the doubles |. You then check what's left if you remove every common element with the Except method. If there's nothing left (the ! [...] .Any(), .Count() == 0 would be valid too), they both contain the same elements.

C# dedupe List based on split

I'm having a hard time deduping a list based on a specific delimiter.
For example I have 4 strings like below:
apple|pear|fruit|basket
orange|mango|fruit|turtle
purple|red|black|green
hero|thor|ironman|hulk
In this example I should want my list to only have unique values in column 3, so it would result in an List that looks like this,
apple|pear|fruit|basket
purple|red|black|green
hero|thor|ironman|hulk
In the above example I would have gotten rid of line 2 because line 1 had the same result in column 3. Any help would be awesome, deduping is tough in C#.
how i'm testing this:
static void Main(string[] args)
{
BeginListSet = new List<string>();
startHashSet();
}
public static List<string> BeginListSet { get; set; }
public static void startHashSet()
{
string[] BeginFileLine = File.ReadAllLines(#"C:\testit.txt");
foreach (string begLine in BeginFileLine)
{
BeginListSet.Add(begLine);
}
}
public static IEnumerable<string> Dedupe(IEnumerable<string> list, char seperator, int keyIndex)
{
var hashset = new HashSet<string>();
foreach (string item in list)
{
var array = item.Split(seperator);
if (hashset.Add(array[keyIndex]))
yield return item;
}
}
Something like this should work for you
static IEnumerable<string> Dedupe(this IEnumerable<string> input, char seperator, int keyIndex)
{
var hashset = new HashSet<string>();
foreach (string item in input)
{
var array = item.Split(seperator);
if (hashset.Add(array[keyIndex]))
yield return item;
}
}
...
var list = new string[]
{
"apple|pear|fruit|basket",
"orange|mango|fruit|turtle",
"purple|red|black|green",
"hero|thor|ironman|hulk"
};
foreach (string item in list.Dedupe('|', 2))
Console.WriteLine(item);
Edit: In the linked question Distinct() with Lambda, Jon Skeet presents the idea in a much better fashion, in the form of a DistinctBy custom method. While similar, his is far more reusable than the idea presented here.
Using his method, you could write
var deduped = list.DistinctBy(item => item.Split('|')[2]);
And you could later reuse the same method to "dedupe" another list of objects of a different type by a key of possibly yet another type.
Try this:
var list = new string[]
{
"apple|pear|fruit|basket",
"orange|mango|fruit|turtle",
"purple|red|black|green",
"hero|thor|ironman|hulk "
};
var dedup = new List<string>();
var filtered = new List<string>();
foreach (var s in list)
{
var filter = s.Split('|')[2];
if (dedup.Contains(filter)) continue;
filtered.Add(s);
dedup.Add(filter);
}
// Console.WriteLine(filtered);
Can you use a HashSet instead? That will eliminate dupes automatically for you as they are added.
May be you can sort the words with delimited | on alphabetical order. Then store them onto grid (columns). Then when you try to insert, just check if there is column having a word which starting with this char.
If LINQ is an option, you can do something like this:
// assume strings is a collection of strings
List<string> list = strings.Select(a => a.Split('|')) // split each line by '|'
.GroupBy(a => a[2]) // group by third column
.Select(a => a.First()) // select first line from each group
.Select(a => string.Join("|", a))
.ToList(); // convert to list of strings
Edit (per Jeff Mercado's comment), this can be simplified further:
List<string> list =
strings.GroupBy(a => a.split('|')[2]) // group by third column
.Select(a => a.First()) // select first line from each group
.ToList(); // convert to list of strings

Categories

Resources