Algorithme de différence directe
-
20-12-2019 - |
Question
Y a-t-il une ou plusieurs fonctions dans std.algorithm
ou std.range
avec lequel calculer paresseusement une différence à terme ?J'en ai besoin pour regrouper différemment les éléments triés (entiers) dans une plage.Il se trouve que les entiers sont SysTime
horodatages.
Mise à jour:Solution proposée:
/** Compute Forward Difference of $(D range).
*/
auto ref forwardDifference(bool reverse = false, Range)(in Range range)
@safe pure nothrow if (isInputRange!Range)
{
import std.algorithm: map;
import std.range: zip, dropOne;
static if (reverse)
return range.zip(range.dropOne).map!(a => a[1] - a[0]);
else
return range.zip(range.dropOne).map!(a => a[0] - a[1]);
}
unittest {
const i = [1, 5, 9, 17];
import std.algorithm: equal;
assert(equal(i.forwardDifference!false, [ -4, -4, -8]));
assert(equal(i.forwardDifference!true, [ +4, +4, +8]));
}
Veuillez commenter la solution.
La solution
Si je te comprends bien, tu veux dire quelque chose comme ça ?
auto i = [1, 5, 9, 17];
writeln(i.zip(i.dropOne()).map!(a=>a[0] - a[1]));
Autres conseils
Une autre façon est de créer votre propre gamme :
import std.range;
import std.stdio;
auto forwardDifference(Range)(Range r) if (isInputRange!Range)
{
struct ForwardDifference
{
Range range;
alias ElementType!Range E;
E _front;
bool needInitialize = true;
this (Range range)
{
this.range = range;
}
E front()
{
if (needInitialize)
{
popFront();
}
return _front;
}
E moveFront()
{
popFront();
return _front;
}
void popFront()
{
if (empty is false)
{
needInitialize = false;
E rf = range.front;
range.popFront();
if (range.empty is false)
{
_front = rf - range.front;
}
}
}
bool empty()
{
return range.empty;
}
}
return ForwardDifference(r);
}
void main(string[] args)
{
auto i = [1, 2, 3, 5, 7, 9];
writeln(i.forwardDifference);
stdin.readln;
}
Notez que, étant donné E e;
, ça ne marche pas quand e-e
est d'un type différent de celui E
lui-même, par exemple lorsque E
est std.datetime.SysTime
sa différence devient de type Duration
et cet algorithme ne parvient pas à instancier.Voici une version corrigée
auto forwardDifference(Range)(Range r) if (isInputRange!Range) {
import std.range: front, empty, popFront;
struct ForwardDifference {
Range _range;
alias E = ElementType!Range;
typeof(_range.front - _range.front) _front;
bool _needInitialize = true;
this (Range range) { this._range = range; }
auto ref front() {
if (_needInitialize) { popFront(); }
return _front;
}
auto ref moveFront() {
popFront();
return _front;
}
void popFront() {
if (empty is false) {
_needInitialize = false;
E rf = _range.front;
_range.popFront();
if (_range.empty is false)
{
_front = _range.front - rf;
}
}
}
bool empty() { return _range.empty; }
}
return ForwardDifference(r);
}
La question naturelle devient maintenant :Quand devrions-nous créer de nouvelles plages spécialisées évaluées paresseusement telles que celle-ci et quand devrions-nous réutiliser et recombiner les plages existantes de std.range
?