Linq - List of List - linq

I have a list like the following
var stringCollection = {"X","1", "2","X","5", "10","X","7", "9"}
Now I need a List of List such that each sub list looks like the following
SibList1 = {"X","1", "2"}
SibList2 = {"X","5", "10"}
SibList3 = {"X","7", "9"}
Is it possible using linq.
Regards
Krish

Try this
string[] stringCollection = { "X", "1", "2", "X", "5", "10", "X", "7", "9" };
int index = 0;
var subLists = stringCollection
.Select(x => new { i = (x == "X" ? ++index : index), s = x })
.GroupBy(x => x.i)
.Select(x => x.Select(y => y.s).ToArray())
.ToArray();

Related

Building LINQ Dynamic Order Clause, But Cast Field

The following code works great of I want to dynamically build an orderby:
public static IQueryable<TEntity> OrderByAnyField<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc, Type propertyType)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return source.Provider.CreateQuery<TEntity>(resultExpression);
}
So, I want to be able to change the CAST of the sort. So, as an example, I would like to take:
.OrderBy(x => x.Something)
and do this instead:
.OrderBy(x => double.Parse(x.Something))
Any help is greatly appreciated
I am sharing one simpler approach to do the same. You can add generics as per your requirement. You can play on data any way you want
static object GetOrder(Table tb, string propertyName, bool desc)
{
if (desc)
return 0;
PropertyInfo pI = typeof(Table).GetProperty(propertyName);
var val = pI.GetValue(tb);
return val;
}
static object GetOrderDesc(Table tb, string propertyName, bool desc)
{
if (!desc)
return 0;
PropertyInfo pI = typeof(Table).GetProperty(propertyName);
var val = pI.GetValue(tb);
return val;
}
static void Main(string[] args)
{
bool desc = false;
List<Table> table = new List<Table>() {
new Table() { ID = "03", X = "Str1", Y = "C1", P = 10 },
new Table() { ID = "04", X = "Str1", Y = "C1", P = 5 },
new Table() { ID = "05", X = "Str1", Y = "C1", P = 1 },
new Table() { ID = "06", X = "Str1", Y = "C1", P = 2 },
new Table() { ID = "07", X = "Str2", Y = "C1", P = 25 },
new Table() { ID = "08", X = "Str2", Y = "C1", P = 4 },
new Table() { ID = "09", X = "Str1", Y = "C2", P = 411 },
new Table() { ID = "10", X = "Str1", Y = "C2", P = 2356 },
new Table() { ID = "11", X = "Str2", Y = "C2", P = 12 },
new Table() { ID = "12", X = "Str2", Y = "C2", P = 33 },
};
var sortedTable = table.OrderBy(x => GetOrder(x, "P", desc)).OrderByDescending(x => GetOrderDesc(x, "P", desc));
}

Entity Framework - Linq : how query to take 2 first ordered and grouped list

I have a large table with 6000000 record like this format(Acc,sDate,Serial,Amount,...)
Acc,date,serial is PKey.
To show my problem, created small code
public class Cheque
{
public string Account{ get; set; }
public string Serial{ get; set; }
public string StartDate { get; set; }
// ... public string Amount { get; set; } ...
}
var list = new List<Cheque>();
list.Add(new Cheque() { Account= "1", Serial = "1", StartDate = "20080120"});
list.Add(new Cheque() { Account= "1", Serial= "2", StartDate = "20080120" });
list.Add(new Cheque() { Account= "1", Serial= "3", StartDate = "20080120" });
list.Add(new Cheque() { Account= "1", Serial= "4", StartDate = "20080120" });
// each acc have 100 to 300 record per date ,for simplicity 3 obj added
list.Add(new Cheque() { Account= "1", Serial= "1", StartDate = "20110120" });
list.Add(new Cheque() { Account= "1", Serial= "2", StartDate = "20110120" });
list.Add(new Cheque() { Account= "1", Serial= "1", StartDate = "20120120" });
list.Add(new Cheque() { Account= "1", Serial= "2", StartDate = "20120120" });
list.Add(new Cheque() { Account= "1", Serial= "3", StartDate = "20120120" });
list.Add(new Cheque() { Account= "2", Serial= "1", StartDate = "20100417" });
list.Add(new Cheque() { Account= "2", Serial= "2", StartDate = "20100417" });
list.Add(new Cheque() { Account= "2", Serial= "1", StartDate = "20120314" });
list.Add(new Cheque() { Account= "2", Serial= "1", StartDate = "20070301" });
list.Add(new Cheque() { Account= "2", Serial= "1", StartDate = "20070301" });
list.Add(new Cheque() { Account= "2", Serial= "1", StartDate = "20070301" });
expected list
only tow set with nearest date from each Account
Acc Serial Date
"1", "1", "20120120" //first resultSet with Account= 1
"1", "2", "20120120"
"1", "3", "20120120"
"1", "1", "20110120" //second resultset with Account= 1
"1", "2", "20110120"
"2", "1", "20120314" //first resultSet with Account= 2
"2", "1", "20100417" //second resultset with Account= 2
"2", "2", "20100417"
plz help me
how can query this with linq
how group by (or distinct ) and take tow first set, like this
The trick is to group by Account and Serial. Take the top two dates and then flatten the list again by SelectMany:
list.GroupBy(x => new {x.Account, x.Serial})
.Select(g => new { FirstTwo = g
.GroupBy(x => x.StartDate).Select(x => x.FirstOrDefault())
.OrderByDescending(x => x.StartDate).Take(2)
})
.SelectMany(g => g.FirstTwo)
.OrderBy(x => x.Account)
.ThenByDescending(x => x.StartDate)
.ThenBy(x => x.Serial)
Result:
1 1 20120120
1 2 20120120
1 3 20120120
1 1 20110120
1 2 20110120
1 3 20110120
2 1 20120314
2 2 20120314
2 1 20100417
2 2 20100417
In order to get the top two from the group the query would be like this:
Update
But in this case, the combination of the Account ID and the Start Date must be unique.
.ToList().GroupBy(x=>new{x.Account,x.StartDate}).SelectMany(y=>y.OrderByDescending(z=>z.StartDate).Take(2));
I am using the similar one in my code and know this works fine.
After searching and reading stackoverflow, make desired result with this code.
var groupedList = (from t in list
group t by new { t.Account, t.StartDate } into g
select new
{
g.Key.Account,
g.Key.StartDate
});
var filteredList = groupedList.GroupBy(x => x.Account)
.SelectMany(g => (from t in g orderby t.StartDate descending select t)
.Take(2).ToList() );
var Result = (from c in list
join k in filteredList on
new { c.StartDate, c.Account } equals
new { k.StartDate, k.Account } //into j
select c).ToList();
/* or lambda method chain
var groupedList = list.GroupBy(t => new {t.StartDate, t.Account})
.Select(g => new { g.Key.StartDate,g.Key.Account})
.GroupBy(x => x.Account)
.SelectMany(g => (from t in g orderby t.StartDate descending select t)
.Take(2).ToList() );
var result = (list.Join(inner: groupedList,
outerKeySelector: c => new {c.StartDate, c.Account},
innerKeySelector: k => new {k.StartDate, k.Account},
resultSelector: (c, k) => c))
.OrderByDescending(e =>e.StartDate).OrderBy(e =>e.Account).ToList();
*/
Console.WriteLine(Result);
Thanks a lot LINQPAD(the best tool for linq) and all friends in stackoverflow (the best and professional developers in the world)
but i guess my code is very complex (3 level filtering) and have not best performance. :)
who have a better offer, please let me know.
I'd love to get some improvements!
At last i find one statement which produce desired result.
var result = (from cheque in list.OrderBy(a => a.Account).ThenByDescending(a => a.StartDate)
group cheque by new { cheque.Account, cheque.StartDate } into gr
//from ids in gr
group gr by gr.Key.Account into secondGrouping
from second in secondGrouping.Distinct().Take(2)
from Cheque f in second
select f
).ToList<Cheque>();

How to Bind dropdown from anonymous class values

I want to populate a dropdown with values A,Band C.The below code works for create only,not for edit.
ViewBag.UserType = new[] { new SelectListItem { Text = "A", Value = "1", Selected = false }, new SelectListItem { Text = "B", Value = "2", Selected = false }, new SelectListItem { Text = "C", Value = "3", Selected = false } };
So I created an anonymous class. I have an anonymous class like below.
var Roles= new[]
{ new { Id =1,UserType="A" },
new {Id=2,UserType="B" },
new {Id=3,UserType="B" }
};
ViewBag.Type = Roles.ToList();
But i dont know how to fill dropdown in View.
#Html.DropDownListFor(model => model.UserType, ((IEnumerable<SelectListItem>)ViewBag.UserType).Select(option => new SelectListItem
{
Text = (option == null ? "None" : option.Text),
Value = option.Value.ToString(),
Selected = (Model != null) && (option.Value == (Model.UserType).ToString())
}),"Select")
What changes should i make in the view
Add following properties to your ViewModel class -
public SelectList Roles
{
get
{
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem
{
Value = "1",
Text = "A",
});
items.Add(new SelectListItem
{
Value = "2",
Text = "B",
});
items.Add(new SelectListItem
{
Value = "3",
Text = "C",
});
return new SelectList(items, "Value", "Text");
}
}
public int SelectedRole { get; set; }
and bind in View as follows -
#Html.DropDownListFor(model => model.SelectedRole, Model.Roles)

Linq GroupBy and Aggregate

Given the following list:
var data = new[]
{
new {category = "Product", text = "aaaa"},
new {category = "Product", text = "bbbb"},
new {category = "Product", text = "bbbb"},
};
how do I group it by category and return an object with category and a description of the different text put together ??
ie. would like to end yp with:
{
categroy="Product"
description = "aaaa,bbbb,cccc"
}
tried the following GroupBy and Aggregate, but something is not right
data.GroupBy(x => x.category).Select(g => new
{
category = g.Key,
description = g.Aggregate((s1, s2) => s1 + "," + s2)
});
TIA
Why don't you use String.Join(IEnumerable) method?
data.GroupBy(x => x.category).Select(g => new
{
category = g.Key,
description = String.Join(",", g.Select(x => x.text))
});
With Aggregate you should do following:
description = g.Aggregate(string.Empty, (x, i) => x + "," + i.text)
First parameter sets seed start value to String.Empty. Second parameter defines method to concatenate current seed value (string) with current element (anonymous_type).
data.GroupBy(x => x.category).Select(g => new
{
category = g.Key,
description = g.Select(x => x.text).Aggregate((s1, s2) => s1 + "," + s2)
});

How to walk through a SelectListItem Array with Linq - techniques?

Linq – Newbie question:
string[] grades = { "2", "5", "1", "7", "4", "8", "6", "0", "9", "3" };
List<SelectListItem> xValues = new List<SelectListItem>()
{ new SelectListItem
{ Selected = true,
Text = "Select...",
Value = "Select...",
}
};
for (int a = 0; a < 10; a++)
{
xValues.Add(new SelectListItem
{ Selected = false,
Text = grades[a],
Value = grades[a]
}
);
}
My application works very fine up to this point.
xValues contains now 11 elements. Each element contains a "Selected", "Text" and "Value" property. "Selected" is only in the first element set to "true".
The second elements contains a "2" in "Text" and "Value", the third element contains a “5”, the fourth contains a “1” and so on...
Question:
How to set "Selected" to "true" in that xValue element which contains a "5" in the "Text" (and in the "Value") property?
Note, that not the 6th element contains (necessarily) the searched "5"!
I believe it must be something like that:
for (int i = 0; i < ponyValues.Count(); i++)
{
xValues[i].Selected = false;
if (xValues.First().Value == “5”)
{
xValues[i].Selected = true;
}
}
Of course is ".First()" wrong... but what would be correct?
var five = xValues.FirstOrDefault(x=> x.Value == "5");
if (five != null)
five.Selected = true;
SelectListItem item = xValues.Single(item => item.Value == 5);
item.Selected = true;
Please note that this will throw an exception if there isn't exactly one item with a value of 5.
var xValues = grades.Select(g => new SelectListItem
{
Selected = (g == "5")
Text = g,
Value = g
})
.ToList();
xValues.Insert(0, new SelectListItem
{
Selected = false,
Text = "Select...",
Value = "Select...",
});
Thanks to all!
Finally I do this
var isSelected = xValues.FirstOrDefault(x => x.Selected == true);
var mustBeSelected = xValues.FirstOrDefault(x => x.Value == "5");
if ((isSelected != null) && (mustBeSelected != null))
{
isSelected.Selected = false;
mustBeSelected.Selected = true;
}
because I want also to set "Selected" to "false" for the very first element.
Sorry forgot to you tell this ;-)

Resources