Why is .array necessary after .group to use .sort? - functional-programming

Having the following piece of code:
import std.algorithm : filter, canFind, map, splitter, group, sort;
import std.stdio : File, writefln;
import std.range : array;
void main(string[] args)
{
string filename = "/var/log/dpkg.log";
string term = args[1];
auto results = File(filename, "r")
.byLine
.filter!(a => canFind(a, term))
.map!(a => splitter(a, ":").front)
.group
.array // why is this crucial ?
.sort!((a,b) => a[1] > b[1]);
foreach (line; results)
writefln("%s => %s times", line[0], line[1]);
}
I have discovered that I desperately need the .array after .group. Can anyone tell me why is that?
As soon as I get rid of it I get the following compiler error:
main.d(16): Error: template std.algorithm.sorting.sort cannot deduce function from argument types !((a, b) => a[1] > b[1])(Group!("a == b", MapResult!(__lambda3, FilterResult!(__lambda2, ByLine!(char, char))))), candidates are:
/usr/include/dmd/phobos/std/algorithm/sorting.d(1830): std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r) if ((ss == SwapStrategy.unstable && (hasSwappableElements!Range || hasAssignableElements!Range) || ss != SwapStrategy.unstable && hasAssignableElements!Range) && isRandomAccessRange!Range && hasSlicing!Range && hasLength!Range)

The result of group is a lazily-evaluated sequence, but sort requires its full input to be fully in-memory, e.g. an array. The array function takes the lazy sequence produced by group and stores it into an array which sort is able to act upon.

Related

How efficiently to convert one dimensional array to two dimensional array in swift3

What is the efficient way to convert an array of pixelValues [UInt8] into two dimensional array of pixelValues rows - [[UInt8]]
You can write something like this:
var pixels: [UInt8] = [0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15]
let bytesPerRow = 4
assert(pixels.count % bytesPerRow == 0)
let pixels2d: [[UInt8]] = stride(from: 0, to: pixels.count, by: bytesPerRow).map {
Array(pixels[$0..<$0+bytesPerRow])
}
But with the value semantics of Swift Arrays, all attempt to create new nested Array requires copying the content, so may not be "efficient" enough for your purpose.
Re-consider if you really need such nested Array.
This should work
private func convert1Dto2DArray(oneDArray:[String], stringsPerRow:Int)->[[String]]?{
var target = oneDArray
var outOfIndexArray:[String] = [String]()
let reminder = oneDArray.count % stringsPerRow
if reminder > 0 && reminder <= stringsPerRow{
let suffix = oneDArray.suffix(reminder)
let list = oneDArray.prefix(oneDArray.count - reminder)
target = Array(list)
outOfIndexArray = Array(suffix)
}
var array2D: [[String]] = stride(from: 0, to: target.count, by: stringsPerRow).map {
Array(target[$0..<$0+stringsPerRow])}
if !outOfIndexArray.isEmpty{
array2D.append(outOfIndexArray)
}
return array2D
}

How to optimize this loop into one linq query removing the loop call entirely?

I have this loop that builds these IEnumerables one by one, I'd like to be able to optimize this so that it can make the call and build all of these IEnumerables at once in one IEnumerable instead of a list of them as the loop has to do. The code is grouping FilteredCases (cases of different types of trees in one year) by month and calculating the percentage of trees for that month compared to the whole year. My problem is that I am doing this separately for each year and would like to do this in one LINQ call hopefully by grouping the correct data together.
Here's the code:
var seriesDataLineList = new List<IEnumerable<SeriesDataPointArray>>();
foreach (var tree in trees)
{
IEnumerable<SeriesDataPointArray> seriesDataLine = months.Select(month => new SeriesDataPointArray()
{
X = month.LookupMonthName,
Y = new object[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId) / (double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) }
});
seriesDataLineList.Add(seriesDataLine);
}
My attempt at doing this with LINQ:
var test = from fc in FilteredCases
group fc by new { fc.Tree, fc.Month }
into casesGrouped
orderby casesGrouped.Key.Tree
select new { casesGrouped.Key.Tree, casesGrouped.Key.Month, count = casesGrouped.Count() };
But I'm not sure how to get these into one IEnuerable<SeriesDataPointArray>
What you have above is a mix of loops and linq, which can get confusing because you are mixing iterative with set based logic. If you expand the code out as just loops, you may find it easier to translate to linq.
As all loops
var seriesDataLineList = new List<SeriesDataPointArray>();
foreach (var tree in trees)
{
foreach (var month in months)
{
var seriesDataLine = new SeriesDataPointArray()
{
X = month.LookupMonthName,
Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId) / (double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) }
};
seriesDataLineList.Add(seriesDataLine);
};
}
Once you get the code in all loops, converting to linq is fairly straight forward. Nested loops are functionally equivalent a cartesian product, which syntactically in linq can be achieved by multiple uncorrelated for statements.
var results = from tree in trees
from month in months
select new SeriesDataPointArray()
{
X = month.LookupMonthName,
Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId) / (double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) }
};
Or in lambda, multiple nested select statements. You'll need a SelectMany() in there somewhere to flatten out the nested collections.
var results = trees.Select(tree =>
months.Select(month =>
new SeriesDataPointArray()
{
X = month.LookupMonthName,
Y = new double[] { Math.Round(FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId && fc.LookupMonthId == month.LookupMonthId) / (double)FilteredCases.Count(fc => fc.LookupTreeId == tree.LookupTreeId) * 100, 0) }
}
)
).SelectMany(x => x);

XtraGrid AutoFilterRow custom range filtering

I'm trying to improve the AutoFilterRow functionality for one of my columns. The column will always consist of a string that represents a range of values like this: "num1 - num2". I would like to allow end users to type a value into the cell in the AutoFilterRow and in this particular column and the rows whose sections have a range that includes the number they typed. For instance, if I had 3 rows and each of their section attributes were the following: "1 - 4", "1 - 6", and "4 - 6", and a user types "3" into the AutoFilterRow cell for this column, I would expect the rows containing "1 - 4" and "1 - 6".
I have already overwritten the CreateAutoFilterCriterion in MyGridView to allow for additional operators as suggested in several examples found on this site:
protected override CriteriaOperator CreateAutoFilterCriterion(GridColumn column, AutoFilterCondition condition, object _value, string strVal)
{
if ((column.ColumnType == typeof(double) || column.ColumnType == typeof(float) || column.ColumnType == typeof(int)) && strVal.Length > 0)
{
BinaryOperatorType type = BinaryOperatorType.Equal;
string operand = string.Empty;
if (strVal.Length > 1)
{
operand = strVal.Substring(0, 2);
if (operand.Equals(">="))
type = BinaryOperatorType.GreaterOrEqual;
else if (operand.Equals("<="))
type = BinaryOperatorType.LessOrEqual;
else if (operand.Equals("<>"))
type = BinaryOperatorType.NotEqual;
}
if (type == BinaryOperatorType.Equal)
{
operand = strVal.Substring(0, 1);
if (operand.Equals(">"))
type = BinaryOperatorType.Greater;
else if (operand.Equals("<"))
type = BinaryOperatorType.Less;
else if (operand.Equals("!") || operand.Equals("~"))
type = BinaryOperatorType.NotEqual;
}
if (type != BinaryOperatorType.Equal)
{
string val = strVal.Replace(operand, string.Empty);
try
{
if (!val.IsEmpty())
{
if (column.ColumnType == typeof(double))
{
var num = Double.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
if (column.ColumnType == typeof(float))
{
var num = float.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
else
{
var num = int.Parse(val, NumberStyles.Number, column.RealColumnEdit.EditFormat.Format);
return new BinaryOperator(column.FieldName, num, type);
}
}
// DateTime example:
// DateTime dt = DateTime.ParseExact(val, "d", column.RealColumnEdit.EditFormat.Format);
// return new BinaryOperator(column.FieldName, dt, type);
}
catch
{
return null;
}
}
}
//
// HERE IS WHERE I WANT TO ADD THE FUNCTIONALITY I'M SPEAKING OF
//
else if (column.FieldName == "SectionDisplayUnits")
{
try
{
if (!strVal.IsEmpty())
{
}
}
catch
{
return null;
}
}
return base.CreateAutoFilterCriterion(column, condition, _value, strVal);
}
How would I go about doing that? I figure I want to split each string with a call to Split(...) like this: cellString.Split(' - '). Then I would parse each string returned from the call to Split(...) into a number so that I could use inequality operators. But I'm just not sure how to go about doing this. Can I get some help? Thanks!
Update:
Please take a look here for a more in-depth discussion on this matter with myself and a knowledgeable DevExpress representative. I received a lot of help and I wanted to share this knowledge with whoever needs similar assistance. Here is the link.
Using C#, you would split the value into two parts, convert them to the number, and compare the value entered by the user with both values to ensure that it is greater or equal the first part and less or equal the second part.
In Criteria Language, the same functionality can be created using Function Operators. However, the expression will be a bit complex. Please try the following. It will work only if the format of values in the SectionDisplayUnits column is fixed, and the value always consists of two numbers delimited by "-".
string rangeDelimiter = "-";
return CriteriaOperator.Parse("toint(trim(substring(SectionDisplayUnits, 0, charindex(?, SectionDisplayUnits)))) <= ? && toint(trim(substring(SectionDisplayUnits, charindex(?, SectionDisplayUnits) + 1, len(SectionDisplayUnits) - charIndex(?, SectionDisplayUnits) - 1))) >= ?", rangeDelimiter, _value, rangeDelimiter, rangeDelimiter, _value);

Groovy Collections: count weirdness with Strings

I am trying to count string values in a member of an object. I have tried three ways, but only one works. I am fine with the one that works, but I can't understand why the others fail. Here's the code:
void testCount() {
TestObj a = new TestObj()
TestObj b = new TestObj()
TestObj c = new TestObj()
a.s = "one"
b.s = "two"
c.s = "two"
def list = [a, b, c]
def count = 0
list.each{
if (it.s.equals("two"))
count++
}
assertTrue("each test failed", count == 2)
assertTrue("collectAll test failed", list.collectAll{ it.s.equals("two")}.size() == 2)
assertTrue("count test failed", list.count{ it.s.equals("two")} == 2)
}
I would expect the Closures passed to collectAll and count to do the same thing I'm doing in my each method. But in the case of collectAll it returns all 3 of the objects and in the case of count it always returns 0.
What am I missing?
collectAll is recursively going through your list, and returning a boolean (as that is what your closure returns for each element in the List)...
So, you get [ false, true, true ], which has 3 elements...
For count,
list.count{ it.s == "two" }
Returns 2 (as expected)
btw: you can do it.s == 'two' in groovy.. no need for all the .equals( "two" )
Edit... Example for count:
class TestObj {
String s
}
list = [ new TestObj( s:'one' ), new TestObj( s:'two' ), new TestObj( s:'two' ) ]
println( list.count { it.s == 'two' } )
Prints 2 for me...
edit 2
Found the cause (from comment below), count didn't accept a closure as a parameter till 1.8 so you'll be calling the object version which will tell you how many times an instance of the closure exists in the list (which is none, as it says)

Correct way to access Multi-Dimensional Array with string indexes in Lua?

I'm trying to have a good access to multi-dimensional arrays with string indexes in Lua, here's basically what I'm trying to do:
rules =
{
{"S_RIGHT", "A_STOP", "S_RESULT"},
}
matrix = {}
for _,v in pairs(rules) do
if( matrix[ v[1] ] == nil ) then
matrix[ v[1] ] = {}
end
matrix[ v[1] ][ v[2] ] = v[3]
end
-- results in error ( attempt to index field 'S_NO' a nil value)
var = matrix["S_NO"]["S_RESULT"]
assert(var == nil, "Var should be nil")
A way to do it but quite verbose is:
var = matrix["S_NO"]
if var ~= nil then
var = var["S_RESULT"]
end
assert(var == nil, "Var should be nil")
Is there a way to make the first case to work ? ( less verbose )
Ok,
Found the answer.
If matrix is going to be read-only a correct approach would be:
local empty = {}
setmetatable(matrix, {__index=function() return empty end})
If I would like to allow writes and it's specifically two levels of tables, I could do:
setmetatable(matrix, {__index=function(t,k) local new={} rawset(t,k,new) return new end}
Hope this helps!

Resources