Deedle FillMissing() function bug? - c#

I work with Deedle v.1.2.5 on C# and do get strange behavior.
When I replace missing values with FillMissing(double.NaN) function, it works as expected, but FillMissing((x) => double.NaN) code will not replace missing values.
What am I doing wrong?
//unitest
[Test]
public void Missing()
{
var sb = new SeriesBuilder<int, double>() { { 1, double.NaN }, { 2, 2 } };
var serie = sb.Series;
//replaces missing with NaN
var res = serie.FillMissing(double.NaN);
//ok
Assert.AreEqual(double.NaN, res.FirstValue());
var sb2 = new SeriesBuilder<int, double>() { { 1, double.NaN }, { 2, 2 } };
var serie2 = sb2.Series;
//NOT replaces missing with NaN
var res2 = serie2.FillMissing((x) => double.NaN);
//crashes
Assert.AreEqual(double.NaN, res2.FirstValue());
}

Related

Change big collection into unique List of collections

I have a big list of objects and in this object there is a category ID something like:
var list = new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 1, Value = new { }},
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 3, Value = new { }}
// and so on
};
So I am looking for making this complicated list more organized like list of lists of unique elements
something like:
var result = new List<List<Example>>
{
new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }},
new Example {CatId = 3, Value = new { }}
},
new List<Example>
{
new Example {CatId = 1, Value = new { }},
new Example {CatId = 2, Value = new { }}
},
new List<Example>
{
new Example {CatId = 1, Value = new { }}
}
}
Problem is I do not what to use, group by will not fix my case, so how to do this in most efficient way.
So this is about partitioning, it's the sort of thing that is easy to do in a database query, but in c# you need to create some key with a partition number that you can then use to .GroupBy.
The partitioning itself is a grouping
var projected = list.GroupBy(x => x.CatId)
.SelectMany( g => g.Select( ( x, i ) => new { Item = x, rn = i + 1 } ) );
This gives you records that look like:
{"Item":{"CatId":1,"Value":{}},"rn":1}
{"Item":{"CatId":1,"Value":{}},"rn":2}
{"Item":{"CatId":1,"Value":{}},"rn":3}
{"Item":{"CatId":2,"Value":{}},"rn":1}
{"Item":{"CatId":2,"Value":{}},"rn":2}
{"Item":{"CatId":3,"Value":{}},"rn":1}
As you can see that rn ("row number") value can be used to group by:
var result = projected.GroupBy(x => x.rn, x => x.Item);
This gives us:
[{"CatId":1,"Value":{}},{"CatId":2,"Value":{}},{"CatId":3,"Value":{}}]
[{"CatId":1,"Value":{}},{"CatId":2,"Value":{}}]
[{"CatId":1,"Value":{}}]
So, all in 1 go:
var result = list.GroupBy(x => x.CatId)
.SelectMany( g => g.Select( ( x, i ) => new { Item = x, rn = i + 1 } ) )
.GroupBy(x => x.rn, x => x.Item);
Live example: https://dotnetfiddle.net/AlTfk8

Using Group by with x amount of elements

Here's a list, think of it as rows and columns where rows are going down and columns are side ways. the column count will always be the same for all rows.
var dataValues = new List<List<string>>()
{
//row 1
new List<string>(){"A","12","X","P8" },
//row 2
new List<string>(){"B","13","Y","P7" },
//row 3
new List<string>(){"C","12","Y","P6" },
//row 4
new List<string>(){"A","14","X","P5" },
//....
new List<string>(){"D","15","Z","P4" },
new List<string>(){"A","13","X","P3" },
new List<string>(){"B","14","Y","P2" },
new List<string>(){"C","13","Z","P1" },
};
The user providers a list of indexes to group by.
var userParam= new List<int>() { 0, 2 };
my question is how do i dynamically group dataValues by the userParam where user param is n amount of index. In the example above it will gorup by the first column and the 3rd. However the index can change and the amount of indexes can change aswell
example
var userParam2 = new List<int>() { 0, 2};
var userParam3 = new List<int>() { 0};
var userParam4 = new List<int>() { 0,1,2};
i know how to group by when i know how many indexes there will be (the the case below it's 2 index parameters), however when it's dynamic (x amount) then i do not know how to do this
var result = dataValues.GroupBy(e => new { G1 = e[userParam2 [0]], G2 = e[userParam2 [1]] });
You could use a Custom Comparer to achieve this :
1 - Declaration of GroupByComparer that inherit from IEqualityComparer :
public class GroupByComparer : IEqualityComparer<List<string>>
{
private static List<int> _intList;
public GroupByComparer(List<int> intList)
{
_intList = intList;
}
public bool Equals(List<string> x, List<string> y)
{
foreach (int item in _intList)
{
if (x[item] != y[item])
return false;
}
return true;
}
public int GetHashCode(List<string> obj)
{
int hashCode = 0;
foreach (int item in _intList)
{
hashCode ^= obj[item].GetHashCode() + item;
}
return hashCode;
}
}
2 - Call group by with EqualityComparer like :
var userParam = new List<int>() { 0, 2 };
var result = dataValues.GroupBy(e => e, new GroupByComparer(userParam));
I hope you find this helpful.
I believe i have something but this looks slow please let me know if there is anyway better of doing this.
var userParams = new List<int>() { 0, 2 };
var dataValues = new List<List<string>>()
{
new List<string>(){"A","12","X","P8" },
new List<string>(){"B","13","Y","P7" },
new List<string>(){"C","12","Y","P6" },
new List<string>(){"A","14","X","P5" },
new List<string>(){"D","15","Z","P4" },
new List<string>(){"A","13","X","P3" },
new List<string>(){"B","14","Y","P2" },
new List<string>(){"C","13","Z","P1" },
};
var result = new List<(List<string> Key, List<List<string>> Values)>();
result.Add((new List<string>(), dataValues));
for (int index = 0; index < userParams.Count; index++)
{
var currentResult = new List<(List<string> Key, List<List<string>> Values)>();
foreach (var item in result)
{
foreach (var newGroup in item.Values.GroupBy(e => e[userParams[index]]))
{
var newKey = item.Key.ToList();
newKey.Add(newGroup.Key);
currentResult.Add((newKey, newGroup.ToList()));
}
}
result = currentResult;
}
foreach(var res in result)
{
Console.WriteLine($"Key: {string.Join(#"\", res.Key)}, Values: {string.Join(" | ", res.Values.Select(e=> string.Join(",",e)))}");
}
final result
Key: A\X, Values: A,12,X,P8 | A,14,X,P5 | A,13,X,P3
Key: B\Y, Values: B,13,Y,P7 | B,14,Y,P2
Key: C\Y, Values: C,12,Y,P6
Key: C\Z, Values: C,13,Z,P1
Key: D\Z, Values: D,15,Z,P4

C# LINQ and Pattern Matching challenge

I need a solution that checks whether the content of a string of fixed lenght adheres to a set of rules. If not, I need to retrieve a list of the Rules that failed, the Expected value for each rule, and the Actually value contained within the string.
This is my current solution:
string actual = "628IDENTREGISTER153004085616P30062010EAPFEMPA013.1";
// Dictionary<Tuple<rule, expected>, startingPostion>
var expected = new Dictionary<Tuple<string, string>, int>
{
{new Tuple<string, string>("900052", "628"), 0},
{new Tuple<string, string>("9000250", "IDENTREGISTER1"), 3},
{new Tuple<string, string>("900092", "53004085616"), 17},
{new Tuple<string, string>("900004", "P"), 28},
{new Tuple<string, string>("900089", "30062010"), 29},
{new Tuple<string, string>("900028", "E"), 37},
{new Tuple<string, string>("900029", "A"), 38},
{new Tuple<string, string>("900002", "P"), 39},
{new Tuple<string, string>("900030", "FEMPA013.0"), 40}
};
// Create an IEnumerable of all broken rules
var result = expected.Where(field =>
!field.Key.Item2.Equals(
actual.Substring(field.Value, field.Key.Item2.Length)))
// Prints:
// [(900030, FEMPA013.0), 40]
foreach (var res in result)
Console.WriteLine(res);
I'm sure there’s a better way of solving this problem. Also, as it stands, I’m not entirely satisfied with this solution as it does not give me the actual field.
Thanks.
Any reason you couldn't just wrap the rule along with the inspected portion in a Tuple?
If not, I would do something like this:
var result = from field in expected
let inspected = actual.Substring(field.Value, field.Key.Item2.Length)
where !field.Key.Item2.Equals(inspected)
select (field, inspected);
Which would then, given your example above, output:
([(900030, FEMPA013.0), 40], FEMPA013.1)
You could unpack the rule entry a little further in the select as well, something along the lines of select (field.Key.Item1, field.Key.Item2, inspected);, and you'll end up with a tuple of (RuleId, expected, actual)
You should create a class to represent a rule, and have some helper methods in the class:
public class Rule {
public string RuleName;
public string Expected;
public int StartPos;
public bool IsMatch(string actual) => Field(actual) == Expected;
public string Field(string actual) => actual.Substring(StartPos, Math.Min(Expected.Length, actual.Length-StartPos));
public override string ToString() => $"{{ {RuleName}: #{StartPos}=\"{Expected}\" }}";
}
Now you can just need a List<Rule> to hold the rules:
var expected = new List<Rule> {
new Rule { RuleName = "900052", Expected = "628", StartPos = 0 },
new Rule { RuleName = "9000250", Expected = "IDENTREGISTER1", StartPos = 3 },
new Rule { RuleName = "900092", Expected = "53004085616", StartPos = 17 },
new Rule { RuleName = "900004", Expected = "P", StartPos = 28 },
new Rule { RuleName = "900089", Expected = "30062010", StartPos = 29 },
new Rule { RuleName = "900028", Expected = "E", StartPos = 37 },
new Rule { RuleName = "900029", Expected = "A", StartPos = 38 },
new Rule { RuleName = "900002", Expected = "P", StartPos = 39 },
new Rule { RuleName = "900030", Expected = "FEMPA013.0", StartPos = 40 }
};
And you can find the bad rules and extract the bad fields:
string actual = "628IDENTREGISTER153004085616P30062010EAPFEMPA013.1";
var result = expected.Where(rule => !rule.IsMatch(actual)).Select(rule => new { rule, Actual = rule.Field(actual) });
foreach (var res in result)
Console.WriteLine(res);
// Output is
// { rule = { 900030: #40="FEMPA013.0" }, Actual = FEMPA013.1 }

"select" query using "PetaPoco" ORM

I tried something like the following, but it didn't work.
var _records = new string[] {"SqlServer", "IIS" };
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN rs", new { rs = _records });
and also i have tried another way like the following, but same problem
var _records = new string[] {"SqlServer", "IIS" };
var query = PetaPoco.Sql.Builder.Select("*").From("tblRecords").Where("RecordName IN (#rs)",new { rs = _records });
var result = db.Query<EntityRecords>(query);
The first one should be
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN (#rs)", new { rs = _records });
or
var result = db.Fetch<EntityRecords>(#" select * from tblRecords where RecordName IN (#0)", _records);
The second one I'm not too sure about because the following tests pass
[Fact]
public void Append_GivenArrayAndValue_ShouldBeValid()
{
// Simple collection parameter expansion
_sql = Sql.Builder.Append("#0 IN (#1) #2", 20, new int[] { 1, 2, 3 }, 30);
_sql.SQL.ShouldBe("#0 IN (#1,#2,#3) #4");
_sql.Arguments.Length.ShouldBe(5);
_sql.Arguments[0].ShouldBe(20);
_sql.Arguments[1].ShouldBe(1);
_sql.Arguments[2].ShouldBe(2);
_sql.Arguments[3].ShouldBe(3);
_sql.Arguments[4].ShouldBe(30);
}
[Fact]
public void Append_GivenArrayAndNamedValue_ShouldBeValid1()
{
// Simple collection parameter expansion
_sql = Sql.Builder.Append("#p1 IN (#p2) #p3", new { p1 = 20 }, new { p2 = new int[] { 1, 2, 3 }}, new { p3 = 30 });
_sql.SQL.ShouldBe("#0 IN (#1,#2,#3) #4");
_sql.Arguments.Length.ShouldBe(5);
_sql.Arguments[0].ShouldBe(20);
_sql.Arguments[1].ShouldBe(1);
_sql.Arguments[2].ShouldBe(2);
_sql.Arguments[3].ShouldBe(3);
_sql.Arguments[4].ShouldBe(30);
}

using Linq to partition data into arrays

I have an array of elements where the element has a Flagged boolean value.
1 flagged
2 not flagged
3 not flagged
4 flagged
5 not flagged
6 not flagged
7 not flagged
8 flagged
9 not flagged
I want to break it into arrays based on the flagged indicator
output >
array 1 {1,2,3}
array 2 {4,5,6,7}
array 3 {8,9}
Linq doesn't have an operator for this, but I've written an extension method that you may be able to use (in the process of submitting it to MoreLinq, which you should also check out):
Using the operator below, you would write:
var result =
items.Segment( (item,prevItem,idx) => item.Flagged )
.Select( seq => seq.ToArray() ) // converts each sequence to an array
.ToList();
Here's the code of the extension method:
public static IEnumerable<IEnumerable<T>> Segment<T>(IEnumerable<T> sequence, Func<T, T, int, bool> newSegmentIdentifier)
{
var index = -1;
using (var iter = sequence.GetEnumerator())
{
var segment = new List<T>();
var prevItem = default(T);
// ensure that the first item is always part
// of the first segment. This is an intentional
// behavior. Segmentation always begins with
// the second element in the sequence.
if (iter.MoveNext())
{
++index;
segment.Add(iter.Current);
prevItem = iter.Current;
}
while (iter.MoveNext())
{
++index;
// check if the item represents the start of a new segment
var isNewSegment = newSegmentIdentifier(iter.Current, prevItem, index);
prevItem = iter.Current;
if (!isNewSegment)
{
// if not a new segment, append and continue
segment.Add(iter.Current);
continue;
}
yield return segment; // yield the completed segment
// start a new segment...
segment = new List<T> { iter.Current };
}
// handle the case of the sequence ending before new segment is detected
if (segment.Count > 0)
yield return segment;
}
}
I had a similar problem with this, and solved it using GroupBy and closure.
//sample data
var arrayOfElements = new[] {
new { Id = 1, Flagged = true },
new { Id = 2, Flagged = false },
new { Id = 3, Flagged = false },
new { Id = 4, Flagged = true },
new { Id = 5, Flagged = false },
new { Id = 6, Flagged = false },
new { Id = 7, Flagged = false },
new { Id = 8, Flagged = true },
new { Id = 9, Flagged = false }
};
//this is the closure which will increase each time I see a flagged
int flagCounter = 0;
var query =
arrayOfElements.GroupBy(e =>
{
if (e.Flagged)
flagCounter++;
return flagCounter;
});
What it does is grouping on an int (flagCounter), which is increased each time a Flagged element is found.
Please note this won't work with AsParallel().
Testing the results:
foreach(var group in query)
{
Console.Write("\r\nGroup: ");
foreach (var element in group)
Console.Write(element.Id);
}
Outputs:
Group: 123
Group: 4567
Group: 89
Considering:
var arrayOfElements = new[] {
new { Id = 1, Flagged = true },
new { Id = 2, Flagged = false },
new { Id = 3, Flagged = false },
new { Id = 4, Flagged = true },
new { Id = 5, Flagged = false },
new { Id = 6, Flagged = false },
new { Id = 7, Flagged = false },
new { Id = 8, Flagged = true },
new { Id = 9, Flagged = false }
};
You can write:
var grouped =
from i in arrayOfElements
where i.Flagged
select
(new[] { i.Id })
.Union(arrayOfElements.Where(i2 => i2.Id > i.Id).TakeWhile(i2 => !i2.Flagged).Select(i2 => i2.Id))
.ToArray();
This works if your elements are ordered by the Id attribute. If they don't, you'll have to inject a Sequence on your original array, that should be easy to do with linq as well, so you'll get a sequence.
Also, a better alternative should be:
// for each flagged element, slice the array,
// starting on the flagged element until the next flagged element
var grouped =
from i in arrayOfElements
where i.Flagged
select
arrayOfElements
.SkipWhile(i2 => i2 != i)
.TakeWhile(i2 => i2 == i || !i2.Flagged)
.Select(i2 => i2.Id)
.ToArray();
Note that those answers are using pure linq.
I don't think LINQ is the right tool for this task. What about this:
public static List<List<T>> PartitionData<T>(T[] arr, Func<T, bool> flagSelector){
List<List<T>> output = new List<List<T>>();
List<T> partition = null;
bool first = true;
foreach(T obj in arr){
if(flagSelector(obj) || first){
partition = new List<T>();
output.Add(partition);
first = false;
}
partition.Add(obj);
}
return output;
}
A small example, with the Data from Fábio Batistas post:
var arrayOfElements = new[] {
new { Id = 1, Flagged = true },
new { Id = 2, Flagged = false },
new { Id = 3, Flagged = false },
new { Id = 4, Flagged = true },
new { Id = 5, Flagged = false },
new { Id = 6, Flagged = false },
new { Id = 7, Flagged = false },
new { Id = 8, Flagged = true },
new { Id = 9, Flagged = false }
};
var partitioned = PartitionData(arrayOfElements, x => x.Flagged);
I don't think LINQ is suited for this very well. It could be done with Aggregate() but I think you'd be better of just looping with a foreach() building up the result.

Categories