C# implicit conversion error from generic list to Ienumerable - c#

public IEnumerable<XdbActiveDiscipline> GetAllDisciplineDocs(string projectNumber)
{
try
{
// return _MigratorDBContext.XdbActiveDiscipline.Where(x => x.OtProjectNumber == projectNumber && x.IsProcessed==null).ToList();
var val = _MigratorDBContext.XdbActiveDiscipline.Where(x => x.OtProjectNumber == projectNumber && x.IsProcessed == null).OrderBy(x => x.DocumentReference).GroupBy(x => new { x.DocumentReference, x.DocumentRevisionNumber, x.DocumentRevisionObject })
.Select(g => new { g, count = g.Count() })
.SelectMany(t => t.g.Select(b => b)
.Zip(Enumerable.Range(1, t.count), (j, i) => new
{
j.OtProjectNumber,
rn = i
}))
.ToList();
return val;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
return val: Throws the error
And the code is written to add a rownumber() value at the last of the result set (i.e partition by)

Val is List of anonymos , not List < XdbActiveDiscipline > . Change return of the action to this:
return val.Select( i=> new XdbActiveDiscipline{
Id=i.Id,
.... and so on
}).ToArray();

Your return value is not typeof(XdbActiveDiscipline). As you can see the error says missing a cast? and the method expects an IEnumerable of XdbActiveDiscipline in return.
The element you are selecting on the linq query is an anonymous type different from the expected return, you can see that if you hover over the val when instantiating.

Related

How to get distinct values with corresponding data from IEnumerable

I need to be able to return back only the records that have a unique AccessionNumber with it's corresponding LoginId. So that at the end, the data looks something like:
A1,L1
A2,L1
A3,L2
However, my issue is with this line of code because Distinct() returns a IEnumerable of string and not IEnumerable of string[]. Therefore, compiler complains about string not containing a definition for AccessionNumber and LoginId.
yield return new[] { record.AccessionNumber, record.LoginId };
This is the code that I am trying to execute:
internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
var z = data.Select(x => x.AccessionNumber).Distinct();
foreach (var record in z)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
}
That's cause you are selecting only that property AccessionNumber by saying the below
var z = data.Select(x => x.AccessionNumber).Distinct();
You probably want to select entire StudentAssessmentTestData record
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString()).Distinct();
foreach (var record in data)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
Instead of using Distinct, use GroupBy. This:
var z = data.Select(x => x.AccessionNumber).Distinct();
foreach (var record in z)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
should be something like this:
return data.GroupBy(x => x.AccessionNumber)
.Select(r => new { AccessionNumber = r.Key, r.First().LoginId});
The GroupBy() call ensures only unique entries for AccessionNumber and the First() ensures that only the first one LoginId with that AccessionNumber is returned.
This assumes that your data is sorted in a way that if there are multiple logins with the same AccessionNumber, the first login is correct.
If you want to choose distinct values based on a certain property you can do it in several ways.
If it is always the same property you wish to use for comparision, you can override Equals and GetHashCode methods in the StudentAssessmentTestData class, thus allowing the Distinct method to recognize how the classes differ from each other, an example can be found in this question
However, you can also implement a custom IEqualityComparer<T> for your implementation, for example the following version
// Custom comparer taking generic input parameter and a delegate function to do matching
public class CustomComparer<T> : IEqualityComparer<T> {
private readonly Func<T, object> _match;
public CustomComparer(Func<T, object> match) {
_match = match;
}
// tries to match both argument its return values against eachother
public bool Equals(T data1, T data2) {
return object.Equals(_match(data1), _match(data2));
}
// overly simplistic implementation
public int GetHashCode(T data) {
var matchValue = _match(data);
if (matchValue == null) {
return 42.GetHashCode();
}
return matchValue.GetHashCode();
}
}
This class can then be used as an argument for the Distinct function, for example in this way
// compare by access number
var accessComparer = new CustomComparer<StudentTestData>(d => d.AccessionNumber );
// compare by login id
var loginComparer = new CustomComparer<StudentTestData>(d => d.LoginId );
foreach (var d in data.Distinct( accessComparer )) {
Console.WriteLine( "{0}, {1}", d.AccessionNumber, d.LoginId);
}
foreach (var d in data.Distinct( loginComparer )) {
Console.WriteLine( "{0}, {1}", d.AccessionNumber, d.LoginId);
}
A full example you can find in this dotnetfiddle
Add a LinqExtension method DistinctBy as below.
public static class LinqExtensions
{
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
}
Use it in your code like this:
var z = data.DistinctBy(x => x.AccessionNumber);
internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
var z = data.DistinctBy(x => x.AccessionNumber);
foreach (var record in z)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
}
This is the code that finally worked:
internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
var data = DataGetter.GetTestData("MyTestData");
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
var z = data.GroupBy(x => new{x.AccessionNumber})
.Select(x => new StudentAssessmentTestData(){ AccessionNumber = x.Key.AccessionNumber, LoginId = x.FirstOrDefault().LoginId});
foreach (var record in z)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
}
Returns a sequence that looks like similar to this:
Acc1, Login1
Acc2, Login1
Acc3, Login2
Acc4, Login1
Acc5, Login3
You can try this. It works for me.
IEnumerable<StudentAssessmentTestData> data = DataGetter.GetTestData("MyTestData");
data = data.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString());
var z = data.GroupBy(x => x.AccessionNumber).SelectMany(y => y.Take(1));
foreach (var record in z)
{
yield return new[] { record.AccessionNumber, record.LoginId };
}
I'm not 100% sure what you're asking. You either want (1) only records with a unique AccessionNumber , if two or more records had the same AccessionNumber then don't return them, or (2) only the first record for each AccessionNumber.
Here's both options:
(1)
internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
return
DataGetter
.GetTestData("MyTestData");
.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString())
.GroupBy(x => x.AccessionNumber)
.Where(x => !x.Skip(1).Any())
.SelectMany(x => x)
.Select(x => new [] { x.AccessionNumber, x.LoginId });
}
(2)
internal static IEnumerable<string[]> GetTestDataForSpecificItemType(ItemTypes itemTypeCode)
{
return
DataGetter
.GetTestData("MyTestData");
.Where(x => x.ItemTypeCode.Trim() == itemTypeCode.ToString())
.GroupBy(x => x.AccessionNumber)
.SelectMany(x => x.Take(1))
.Select(x => new [] { x.AccessionNumber, x.LoginId });
}

The proper place to add try-catch C#

I want to use try-catch to check being divided by 0 in
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) /
(double)subList.Skip(idx - t + 1).First().Close
...but I don't know where to add try-catch. I try to add including the whole var newList =, but it is not allowed, since variable newList no longer exists later. So where is the proper position to add try-catch?
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
depends on what you're going to do in your catch - if you want newList to have a valid value even if the divisor is 0 then you should probably have your 0 check integrated into the main code flow rather than using exceptional flows.
However, to directly answer your question as written, explicity declare newList to a default value first, then reassign within a try/catch block (place the entirety of the code you've written inside the try, with the explicit default declaration before the try). Then newList will exist when you need to use it later.
If you want to catch everything then
try
{
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
}
catch(Exception ex)
{
//your error
}
You can certainly do this:
var newList = new[]
{
new { Symbol = "", Close = 0.0, Date = DateTime.Now, Vol = 0 }
}.Take(0).ToList();
try
{
var newList = data.GroupBy(o => o.Date).Where(o => o.Key <= Beginday).OrderByDescending(o => o.Key).Take(Y).SelectMany(o => o).GroupBy(x => new { x.Symbol })
.Select
(
x =>
{
var subList = x.OrderBy(y => y.Date).ToList();
return subList.Select((y, idx) =>
{
return new
{
Symbol = y.Symbol,
Close = y.Close,
Date = y.Date,
Vol = (idx < t - 1) ? 0 : new DescriptiveStatistics(subList.Skip(idx - t + 1).Take(t)
.Select(o =>
((double)o.Close - (double)subList.Skip(idx - t + 1).First().Close) / (double)subList.Skip(idx - t + 1).First().Close).ToList()).StandardDeviation,
};
});
}
)
.SelectMany(x => x)
.ToList();
}
catch (Exception ex)
{
}
So long as the names and types are the same in the two anonymous types then this works fine.

Increment in LINQ Query

Hello I have the following code which returns me List of type Listitem. I want to increase the value by one for every ListItem Selected.
public static List<System.Web.UI.WebControls.ListItem> GetMyCompassTUTListContent(List<int> ContentID, Int32 CountryID)
{
int Counter = 0;
List<System.Web.UI.WebControls.ListItem> litems = new List<System.Web.UI.WebControls.ListItem>();
using (DbDataContext objContext = new DbDataContext())
{
if (CountryID == (int)MyCompassBLL.Constants.Country.Australia)
{
litems = objContext.Contents.Where(x => ContentID.Contains(x.ID)).Select(x => new System.Web.UI.WebControls.ListItem { Text = x.Text, y = (y + 1) }).ToList();
}
else
{
litems = objContext.ContentCountries.Where(x => ContentID.Contains(x.ContentID) && x.CountryID == CountryID).Select(x => new System.Web.UI.WebControls.ListItem { Text = x.Text, Value = (Counter + 1).ToString() }).ToList();
}
}
return litems;
}
Please help me in this. I am not able to that since I am not able to find the way of how to reassign value to variable counter after increment.
Thanks in advance
There is an overload of Select that also provides the index of the current item. You can use that. However, most DB query providers don't support it, so you'll need to do your DB query, then ensure that the Enumerable overload of Select is called to add the index:
public static List<ListItem> GetMyCompassTUTListContent(
List<int> ContentID, Int32 CountryID)
{
//Note this is IEnumerable, not IQueryable, this is important.
IEnumerable<string> query;
using (DbDataContext objContext = new DbDataContext())
{
if (CountryID == (int)MyCompassBLL.Constants.Country.Australia)
{
query = objContext.Contents.Where(x => ContentID.Contains(x.ID))
.Select(x => x.Text);
}
else
{
query = objContext.ContentCountries
.Where(x => ContentID.Contains(x.ContentID)
&& x.CountryID == CountryID)
.Select(x => x.Text);
}
return query.Select((text, index) => new ListItem
{
Text = text,
Value = (index + 1).ToString(),
})
.ToList();
}
}
Use ++Counter instead of ( Counter + 1)
[UPDATE]
try to increment your Counter before put it into the Select():
else
{
Counter++;
litems = objContext.ContentCountries.Where(x => ContentID.Contains(x.ContentID) && x.CountryID == CountryID).Select(x => new System.Web.UI.WebControls.ListItem { Text = x.Text, Value = Counter.ToString() }).ToList();
}

Get index of lines that match my linq

I have a linq statement and I would like to know if it is possible to get indicies of lines that match my statement? Here it is:
var result = list3.Where(middle => list4.Any(x => x == middle.Middle.category1)).Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= datetimepickerChoice1 && x.dt <= datetimepickerChoice2)
.Select(x => x.obj).ToList();
You can use the overload of Select (or Where) which projects also the index of the element:
var result = list3.Select((middle, index) => new{ middle, index })
.Where(x => list4.Any(xx => xx == x.middle.Middle.category1))
.Select(x => new { x.middle, x.index, dt = DateTime.ParseExact(x.middle.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.index)
.ToList();
Side-note: consider to change your variable names to be more meaningful. That is unreadable.
do you mean this?
var result = list3.Where(middle => list4.Any(x => x == middle.Middle.category1))
.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select((x,index) =>new{ x.obj,Index=index}).ToList();
Also note that if you want to search for the indicies of items matching a predicate very often, it could be worth writing a very simple extension method:
public static class IEnumerableExt
{
public static IEnumerable<int> FindIndices<T>(this IEnumerable<T> self, Predicate<T> predicate)
{
int i = 0;
foreach (var element in self)
{
if (predicate(element))
yield return i;
++i;
}
}
}
Which you would call like this:
var result = list3.FindIndices(x => list4.Any(xx => xx == x.middle.Middle.category1));

how to deal with exception in LINQ Select statement

I have a LINQ query as follows
m_FOO = rawcollection.Select(p=> p.Split(' ')).Select(p =>
{
int thing = 0;
try
{
thing = CalculationThatCanFail(p[1]);
}
catch{}
return new { Test = p[0], FooThing = thing};
})
.GroupBy(p => p.Test)
.ToDictionary(p => p.Key, s => s.Select(q => q.FooThing).ToList());
So, the CalculationThatCanFail throws sometimes. I don't want to put null in and then filter that out with another Where statement later, and a junk value is equally unacceptable. Does anyone know how to handle this cleanly? Thanks.
EDIT: There's a good reason for the double Select statement. This example was edited for brevity
I'm not clear from question if you mean, you don't want to use null for FooThing or you don't want to use null for the entire anonymously typed object. In any case, would this fit the bill?
m_FOO = rawcollection.Select(p=> p.Split(' ')).Select(p =>
{
int thing = 0;
try
{
thing = CalculationThatCanFail(p[1]);
return new { Test = p[0], FooThing = thing};
}
catch
{
return null;
}
})
.Where(p => p != null)
.GroupBy(p => p.Test)
.ToDictionary(p => p.Key, s => s.Select(q => q.FooThing).ToList());
For these situations I use a Maybe type (similar to this one) for calculations that may or may not return a value, instead of nulls or junk values. It would look like this:
Maybe<int> CalculationThatMayHaveAValue(string x)
{
try
{
return CalculationThatCanFail(x);
}
catch
{
return Maybe<int>.None;
}
}
//...
var xs = ps.Select(p =>
{
Maybe<int> thing = CalculationThatMayHaveAValue(p[1]);
return new { Test = p[0], FooThing = thing};
})
.Where(x => x.FooThing.HasValue);

Categories

Resources