Convert IDictionary<Guid,string> to the IEnumerable<SelectListItem> - c#

How i can convert IDictionary<Guid,string> to the IEnumerable<SelectListItem>?
I want to use string as SelectListItem.

If you want to use the guid as the value, you can use
dictionary.Select(x => new SelectListItem { Text = x.Value, Value = x.Key })

Well you could just use
dictionary.Values().Select(x => new SelectedListItem { Text = x })
Just be aware that it may not be in a useful order: Dictionary<,> is inherently unordered (or rather, the order may change and shouldn't be relied on).

Something like this should do what you want:
var selectList = dictionary
.OrderBy(kvp => kvp.Value) // Order the Select List by the dictionary value
.Select(kvp => new SelectListItem
{
Selected = kvp.Key == model.SelectedGuid, // optional but would allow you to maintain the selection when re-displaying the view
Text = kvp.Value,
Value = kvp.Key
})
.ToList();

Using LINQ, you could do something like,
var theSelectList = from dictItem in dict
select new SelectListItem()
{
Text = dictItem.Value,
Value = dictItem.Key.ToString()
};

Related

Concatenate two fields in select list (C#)

I use a viewbag to create a select list and I want to Show two fields concatenated together. However, it is crashing on my view. Here is the viewbag code:
ViewBag.PackageId = new SelectList(db.Packages.Where(p => p.status == "A"), "u_package_id", "u_package_id" + "'-'" + "package_nme");
This should work
ViewBag.PackageId = db.Packages.Where(p => p.status == "A")
.Select(p => new SelectListItem
{
Text = p.u_package_id + "-" + p.package_nme,
Value = p.u_package_id
};
The 2nd and 3rd parameters of the SelectList constructor are strings that must match the names of properties in your model (in your case your don't have a property named "u_package_id-package_nme" hence the error).
In the controller, generate a collection of SelectListItem
ViewBag.PackageList = db.Packages.Where(p => p.status == "A").Select(p => new SelectListItem()
{
Value = p.u_package_id, // may need .ToString() depending on the property type
Text = string.Format("{0}-{1}", p.u_package_id, p.package_nme)
}
Side note: Suggest you name your properties to reflect what they are (i.e. its a collection of items, not an ID so PackageList, not PackageId) and this would be necessary anyway if the model your binding to contains a property named PackageId
Thanks to deramko, I have my answer. He was 99% of the way there. Here is the final code:
ViewBag.PackageId = db.Packages.Where(p => p.status == "A")
.Select(p => new SelectListItem
{
Text = p.u_package_id + "-" + p.package_nme,
Value = p.u_package_id.ToString()
});

Identifying and grouping similar items in a collection of strings

I have a collection of strings like the following:
List<string> codes = new List<string>
{
"44.01", "44.02", "44.03", "44.04", "44.05", "44.06", "44.07", "44.08", "46", "47.10"
};
Each string is made up of two components separated by a full stop - a prefix code and a subcode. Some of the strings don't have sub codes.
I want to be able combine the strings whose prefixes are the same and output them as follows with the other codes also:
44(01,02,03,04,05,06,07,08),46,47.10
I'm stuck at the first hurdle of this, which is how to identify and group together the codes whose prefix values are the same, so that I can combine them into a single string as you can see above.
You can do:
var query = codes.Select(c =>
new
{
SplitArray = c.Split('.'), //to avoid multiple split
Value = c
})
.Select(c => new
{
Prefix = c.SplitArray.First(), //you can avoid multiple split if you split first and use it later
PostFix = c.SplitArray.Last(),
Value = c.Value,
})
.GroupBy(r => r.Prefix)
.Select(grp => new
{
Key = grp.Key,
Items = grp.Count() > 1 ? String.Join(",", grp.Select(t => t.PostFix)) : "",
Value = grp.First().Value,
});
This is how it works:
Split each item in the list on the delimiter and populate an anonymous type with Prefix, Postfix and original value
Later group on Prefix
after that select the values and the post fix values using string.Join
For output:
foreach (var item in query)
{
if(String.IsNullOrWhiteSpace(item.Items))
Console.WriteLine(item.Value);
else
Console.WriteLine("{0}({1})", item.Key, item.Items);
}
Output would be:
44(01,02,03,04,05,06,07,08)
46
47.10
Try this:-
var result = codes.Select(x => new { SplitArr = x.Split('.'), OriginalValue = x })
.GroupBy(x => x.SplitArr[0])
.Select(x => new
{
Prefix= x.Key,
subCode = x.Count() > 1 ?
String.Join(",", x.Select(z => z.SplitArray[1])) : "",
OriginalValue = x.First().OriginalValue
});
You can print your desired output like this:-
foreach (var item in result)
{
Console.Write("{0}({1}),",item.Prefix,item.subCode);
}
Working Fiddle.
Outlined idea:
Use Dictionary<string, List<string>> for collecting your result
in a loop over your list, use string.split() .. the first element will be your Dictionary key ... create a new List<string> there if the key doesn't exist yet
if the result of split has a second element, append that to the List
use a second loop to format that Dictionary to your output string
Of course, linq is possible too, e.g.
List<string> codes = new List<string>() {
"44.01", "44.05", "47", "42.02", "44.03" };
var result = string.Join(",",
codes.OrderBy(x => x)
.Select(x => x.Split('.'))
.GroupBy(x => x[0])
.Select((x) =>
{
if (x.Count() == 0) return x.Key;
else if (x.Count() == 1) return string.Join(".", x.First());
else return x.Key + "(" + string.Join(",", x.Select(e => e[1]).ToArray()) + ")";
}).ToArray());
Gotta love linq ... haha ... I think this is a monster.
You can do it all in one clever LINQ:
var grouped = codes.Select(x => x.Split('.'))
.Select(x => new
{
Prefix = int.Parse(x[0]),
Subcode = x.Length > 1 ? int.Parse(x[1]) : (int?)null
})
.GroupBy(k => k.Prefix)
.Select(g => new
{
Prefix = g.Key,
Subcodes = g.Where(s => s.Subcode.HasValue).Select(s => s.Subcode)
})
.Select(x =>
x.Prefix +
(x.Subcodes.Count() == 1 ? string.Format(".{0}", x.Subcodes.First()) :
x.Subcodes.Count() > 1 ? string.Format("({0})", string.Join(",", x.Subcodes))
: string.Empty)
).ToArray();
First it splits by Code and Subcode
Group by you Code, and get all Subcodes as a collection
Select it in the appropriate format
Looking at the problem, I think you should stop just before the last Select and let the data presentation be done in another part/method of your application.
The old fashioned way:
List<string> codes = new List<string>() {"44.01", "44.05", "47", "42.02", "44.03" };
string output=""
for (int i=0;i<list.count;i++)
{
string [] items= (codes[i]+"..").split('.') ;
int pos1=output.IndexOf(","+items[0]+"(") ;
if (pos1<0) output+=","+items[0]+"("+items[1]+")" ; // first occurence of code : add it
else
{ // Code already inserted : find the insert point
int pos2=output.Substring(pos1).IndexOf(')') ;
output=output.Substring(0,pos2)+","+items[1]+output.Substring(pos2) ;
}
}
if (output.Length>0) output=output.Substring(1).replace("()","") ;
This will work, including the correct formats for no subcodes, a single subcode, multiple subcodes. It also doesn't assume the prefix or subcodes are numeric, so it leaves leading zeros as is. Your question didn't show what to do in the case you have a prefix without subcode AND the same prefix with subcode, so it may not work in that edge case (44,44.01). I have it so that it ignores the prefix without subcode in that edge case.
List<string> codes = new List<string>
{
"44.01", "44.02", "44.03", "44.04", "44.05", "44.06", "44.07", "44.08", "46", "47.10"
};
var result=codes.Select(x => (x+".").Split('.'))
.Select(x => new
{
Prefix = x[0],
Subcode = x[1]
})
.GroupBy(k => k.Prefix)
.Select(g => new
{
Prefix = g.Key,
Subcodes = g.Where(s => s.Subcode!="").Select(s => s.Subcode)
})
.Select(x =>
x.Prefix +
(x.Subcodes.Count() == 0 ? string.Empty :
string.Format(x.Subcodes.Count()>1?"({0})":".{0}",
string.Join(",", x.Subcodes)))
).ToArray();
General idea, but i'm sure replacing the Substring calls with Regex would be a lot better as well
List<string> newCodes = new List<string>()
foreach (string sub1 in codes.Select(item => item.Substring(0,2)).Distinct)
{
StringBuilder code = new StringBuilder();
code.Append("sub1(");
foreach (string sub2 in codes.Where(item => item.Substring(0,2) == sub1).Select(item => item.Substring(2))
code.Append(sub2 + ",");
code.Append(")");
newCodes.Add(code.ToString());
}
You could go a couple ways... I could see you making a Dictionary<string,List<string>> so that you could have "44" map to a list of {".01", ".02", ".03", etc.} This would require you processing the codes before adding them to this list (i.e. separating out the two parts of the code and handling the case where there is only one part).
Or you could put them into a a SortedSet and provide your own Comparator which knows that these are codes and how to sort them (at least that'd be more reliable than grouping them alphabetically). Iterating over this SortedSet would still require special logic, though, so perhaps the Dictionary to List option above is still preferable.
In either case you would still need to handle a special case "46" where there is no second element in the code. In the dictionary example, would you insert a String.Empty into the list? Not sure what you'd output if you got a list {"46", "46.1"} -- would you display as "46(null,1)" or... "46(0,1)"... or "46(,1)" or "46(1)"?

Update the selected dropdownlist value base on value from another linq query

I use the following code to get the LOV for dropdownlist and setting a selected value as well:
ViewData["dropDown_Color"] = correspondingDropDownValue
.Select(j =>
new SelectListItem {
Text = j.ListOfValue,
Value = j.ListOfValue,
Selected = j.ListOfValue
== x.DefaultValue
})
.ToList();
Now that I have a dropdownlist in my ViewData, I want to update the selected value of this ViewData["dropDown_Color"] base on the following query
var userPref = from m in db.UserColorPref
where m.UserID.Equals(userSessionID)
select m;
The value to be updated can be access by userPref.color. May I know how to achieve my objective?
Use this
List<SelectListItem> selectlist = ViewData["dropDown_Color"] as List<SelectListItem>;
selectlist.ForEach(x =>
{
x.Selected = x.Value == userPref.color;
});
You can achieve it as follows:
ViewData["dropDown_Color"] = new SelectList(YourSelectList, "Value", "Text", selectedValue);

A Dictionary of Dictionary from IQueryable

I would like a method to return a Dictionary of Dictionary from an IQueryable formula. Typically,
Dictionary<int, Dictionary<DateTime, string>>
At first, I looked at ToDictionary() of course but couldn't find a way to declare two one after the other.
Then, i loooked at ToLookup() and I have a way to carry this with a ILookup with the string being my secondary dictionary(the DateTime.Tostring() + the other string)... you follow ? :)
But I don't find the ILookup solution really confortable (parsing a date to string and when i receive the data -> string to date.. beuark)
That would give something like that
return this.ttdc.Trackers.GroupBy(t => new { TrackerTaskId = t.TrackerTaskID, DateGenerated = t.TrackerDateGenerated })
.Select(t => new { taskId = t.Key.TrackerTaskId, DateGenerated = t.Key.DateGenerated, count = t.Count() })
.ToLookup(k => k.taskId.Value, k => k.DateGenerated.Value.ToString() + "|" + k.count);
Now, i'm thinking about creating a List of self created class with the 3 informations I need as properties.
Could you help me chosing the best pattern ? This method is hosted on a windows service and I would like to limit the amount of data transfered to the client.
Thank you
Here's an example, using GroupBy and ToDictionary:
var testValues = new[]{new {ID = 1, Date = new DateTime(2010,1,1), Str = "Val1"},
new {ID = 1, Date = new DateTime(2011,2,2), Str = "Val2"},
new {ID = 2, Date = new DateTime(2010,1,1), Str = "Val3"}};
var dict = testValues.GroupBy(item => item.ID)
.ToDictionary(grp => grp.Key,
grp => grp.ToDictionary(item => item.Date,
item => item.Str));

Create new Dictionary<string, IEnumerable<SelectListItem> type using IDictionary

Hi I have a list of users. Each User belongs to an Area.
What I'm wanting to do with this list is create a dictionary from them where the Area Name is the Key and the value for the key is a selectList of Users in the Area the with a Text value of the Username and a Value set to the User Id.
I managed to achieve this using the following code:
var StaffByArea = new Dictionary<string, IEnumerable<SelectListItem>>();
foreach(var area in areas)) {
var personList = new List<SelectListItem>();
foreach (var person in staff.Where(c => c.AreaId == area.Id)) {
personList.Add(new SelectLis
tItem { Value = person.AreaId.ToString(), Text = person.Username });
}
StaffByArea.Add(area.Name, personList);
}
So for every possible area I'm finding correlating staff and adding them to a selectlist. Once I've added all the people for the area I add that select list to the dictionary with the area name as key.
I've been thinking this maybe easier to do with ToDictionary()
Does anyone know how to do this?
I've only got as far as:
StaffByArea = Users.ToDictionary(x => x.Area.Name, ...);
Try this:
var StaffByArea
= areas.ToDictionary(
a => a.Name,
a => staff
.Where(c => c.AreaId == area.Id)
.Select(c => new SelectListItem
{
Value = c.AreaId.ToString(),
Text = c.Username
}));

Categories

Resources