Travailler avec des rĂšgles peut ĂȘtre dĂ©routant. Imaginez que vous ayez une application de comptabilitĂ©. Et vous devez obtenir les pĂ©riodes pendant lesquelles l'employĂ© a travaillĂ© selon l'horaire «2 Ă 2» avant l'indexation salariale. Dans ce cas, il est nĂ©cessaire de prendre en compte les vacances, les changements d'horaires de travail, les licenciements / rĂ©intĂ©grations, les mutations vers d'autres services et d'autres activitĂ©s du personnel. Ces informations sont stockĂ©es sous forme de commandes, qui ont une «date de dĂ©but» et une «date de fin», c'est-Ă -dire. vous avez des pĂ©riodes de temps pour opĂ©rer.
Par exemple, recherchez l'intersection de tous les intervalles:
2 5 7 9
|--------------| |---------|
0 3 4 6 7 10
|--------------| |---------| |--------------|
1 4 5 8
|--------------| |--------------|
Result
2 3 7 8
|----| |----|
//
L'utilitaire annoncé est destiné à résoudre de tels problÚmes.
Travailler avec des périodes dans la représentation visuelle est beaucoup plus facile, donc pour les tests (il y a aussi un ensemble de tests) et la documentation, j'ai fait une génération simple d'images ASCII, comme indiqué ci-dessus.
, ASCII y=f(x).

1. ASCII Blazor WebAssembly. y x.
IntervalUtility
GitHub, NuGet, demo Blazor WebAssembly.
. GitHub.
var arrayOfArrays = new[] {
new[] { new Interval<int>(2,5), new Interval<int>(7, 9) },
new[] { new Interval<int>(0,3), new Interval<int>(4, 6),
new Interval<int>(7, 10) },
new[] { new Interval<int>(1,4), new Interval<int>(5, 8) },
};
var intervalUtil = new IntervalUtil();
var res = intervalUtil.Intersections(arrayOfArrays);
// => [2,3], [7,8]
2 5 7 9
|--------------| |---------|
0 3 4 6 7 10
|--------------| |---------| |--------------|
1 4 5 8
|--------------| |--------------|
Result
2 3 7 8
|----| |----|
var intervalsA = new[] { new Interval<int>(1, 5), new Interval<int>(7, 10) };
var intervalsB = new[] { new Interval<int>(0, 2), new Interval<int>(3, 5),
new Interval<int>(8, 9) };
var intervalUtil = new IntervalUtil();
var res = intervalUtil.Exclude(intervalsA, intervalsB);
// => [2,3], [7,8], [9,10]
1 5 7 10
|-------------------| |--------------|
0 2 3 5 8 9
|---------| |---------| |----|
Result
2 3 7 8 9 10
|----| |----| |----|
. ASCII .
ASCII
demo Blazor WebAssembly.
â â. /. , â â, , â â - .
: â ASCIIâ ,
( ). ââ . . - . . - .
, :
,
, , .
/ , .
public class DrawerProcessor {
public void Draw(
//
Func<int, int, DrawerBlock> blockDraw,
//
Action<string, bool> onBlockDraw) {
int row = 0;
int blockIndex = 0;
var done = false;
while (!done) {
var block = blockDraw(row, blockIndex);
switch (block.Command) {
case DrawerCommand.Continue:
blockIndex = blockIndex + block.Displacement;
break;
case DrawerCommand.NewLine:
row = row + 1;
blockIndex = 0;
break;
case DrawerCommand.End:
done = true;
break;
}
onBlockDraw(block.Value, done);
}
}
}
public class DrawerBlock {
public string Value { get; set; }
public DrawerCommand Command { get; set; }
// ,
// Value
// Value 2
public int Displacement { get; set; } = 1;
}
DrawerProcessor . DrawerProcessor :
,
,
.
DrawerProcessor:
var drawer = new DrawerProcessor();
drawer.Draw(
(row, blockIndex) => {
//
if (row == 3)
return new DrawerBlock {
Command = DrawerCommand.End
};
if(blockIndex == 3)
return new DrawerBlock {
Value = Environment.NewLine,
Command = DrawerCommand.NewLine
};
return new DrawerBlock {
Value = $"[{row},{blockIndex}]",
Command = DrawerCommand.Continue
};
},
(blockStr, isEnd) => Console.Write(blockStr)
);
[0,0][0,1][0,2]
[1,0][1,1][1,2]
[2,0][2,1][2,2]
// 1. DrawerProcessor.
// -
// ( (row, blockIndex) => { .. }),
// .
, , DrawerBlock.Displacement? - 1 , :
8 11
|---------|
â11â - . â11â - , â â11â, â1â - â1â â. ? â11â : DrawerBlock.Displacement = 2.
: â11â , (, -). ( â1â - â1â), .. " ". .
:
static class Block {
public static DrawerBlock Continue(string val, int displacement = 1)
=> new() {
Command = DrawerCommand.Continue,
Value = val,
Displacement = displacement
};
public static DrawerBlock End() =>
new() { Command = DrawerCommand.End };
public static DrawerBlock NewLine() =>
new() {
Command = DrawerCommand.NewLine,
Value = Environment.NewLine
};
}
:
return new DrawerBlock {
Value = Environment.NewLine,
Command = DrawerCommand.NewLine
};
:
return Block.NewLine();
1 ( (row, blockIndex) => { .. }). , . , / - (row, blockIndex) => { .. } .
: 1 :
[0,0][0,1][0,2]
[1,0][1,1][1,2]
[2,0][2,1][2,2]
:
[ ][0,1][ ]
[1,0][ ][1,2]
[ ][2,1][ ]
(row, blockIndex) => { .. }.
: â /â - , .. â â - . â â - .
.. , (. ), . .
. (â â, â â, â â, â â) ().
// ""
DrawerBlock end(int row, int blockIndex) =>
row == 3 ? Block.End() : null;
// " "
DrawerBlock newLine(int row, int blockIndex) =>
blockIndex == 3 ? Block.NewLine() : null;
// " "
DrawerBlock brick(int row, int blockIndex) =>
Block.Continue($"[{row},{blockIndex}]");
:
public class BlockDrawer {
readonly DrawerProcessor _DrawerProcessor;
public BlockDrawer(DrawerProcessor drawerProcessor) {
_DrawerProcessor = drawerProcessor
?? throw new ArgumentNullException(nameof(drawerProcessor));
}
public void Draw(
IReadOnlyCollection<Func<int, int, DrawerBlock>> blockDrawers,
Action<string, bool> onBlockDraw) {
_DrawerProcessor.Draw(
(row, blockIndex) => {
foreach (var bd in blockDrawers) {
var block = bd(row, blockIndex);
if (block != null)
return block;
}
return
new DrawerBlock { Command = DrawerCommand.End };
},
onBlockDraw
);
}
}
:
// :
var blockDrawers = new Func<int, int, DrawerBlock>[] {
end,
newLine,
brick
};
var drawer = new DrawerProcessor();
var blockDrawer = new BlockDrawer(drawer);
blockDrawer.Draw(
blockDrawers,
(blockStr, isEnd) => Console.Write(blockStr));
, 1 - .
:
static void Main(string[] args) {
DrawerBlock end(int row, int blockIndex) => ...;
DrawerBlock newLine(int row, int blockIndex) => ...;
DrawerBlock brick(int row, int blockIndex) => ...;
//
DrawerBlock brickEmpty(int row, int blockIndex) =>
((row + blockIndex) % 2 == 0) ? Block.Continue($"[ ]") : null;
var blockDrawers = new Func<int, int, DrawerBlock>[] {
end,
newLine,
brickEmpty, // brick
brick
};
var drawer = new DrawerProcessor();
var blockDrawer = new BlockDrawer(drawer);
blockDrawer.Draw(
blockDrawers,
(blockStr, isEnd) => Console.Write(blockStr));
}
[ ][0,1][ ]
[1,0][ ][1,2]
[ ][2,1][ ]
// 2. DrawerProcessor.
// .
// main - ,
// .
: â â. . . , . , - .
2 Main. Main. . .
public interface IContextDrawerBlock<TDrawerContext> {
int Priority { get; }
DrawerBlock Draw(int row, int blockIndex, TDrawerContext context);
}
context, . , - context.RowCount:
class EndDrawer : IContextDrawerBlock<SampleDrawContext> {
public int Priority => 10;
public DrawerBlock Draw(int row, int blockIndex,
SampleDrawContext context)
=> row == context.RowCount ? Block.End() : null;
}
, :
public class ContextBlockDrawer<TDrawerContext> {
readonly IReadOnlyCollection<IContextDrawerBlock<TDrawerContext>> _BlockDrawers;
readonly BlockDrawer _Drawer;
public ContextBlockDrawer(
BlockDrawer drawer,
IReadOnlyCollection<IContextDrawerBlock<TDrawerContext>> blockDrawers) {
_Drawer = drawer ?? throw ...
_BlockDrawers = blockDrawers?.Any() == true
? blockDrawers.OrderBy(bd => bd.Priority).ToArray()
: throw ...
}
public void Draw(TDrawerContext drawerContext,
Action<string, bool> onBlockDraw) {
var drawers = _BlockDrawers.Select(bd => {
DrawerBlock draw(int row, int blockIndex) =>
bd.Draw(row, blockIndex, drawerContext);
return (Func<int, int, DrawerBlock>)draw;
})
.ToArray();
_Drawer.Draw(drawers, onBlockDraw);
}
}
:
// ContextBlockDrawer
var drawer = new DrawerProcessor();
var blockDrawer = new BlockDrawer(drawer);
var blockDrawers = new IContextDrawerBlock<SampleDrawContext>[] {
new EndDrawer(),
new EndLineDrawer(),
new BrickEmptyDrawer(),
new BrickDrawer(),
};
var ctxBlockDrawer = new ContextBlockDrawer<SampleDrawContext>(
blockDrawer,
blockDrawers);
// ContextBlockDrawer
ctxBlockDrawer.Draw(
new SampleDrawContext {
RowCount = 3,
BlockCount = 3
},
(blockStr, isEnd) => Console.Write(blockStr));
// 3. ContextBlockDrawer.
// .
// .
// ,
// - Priority.
: Priority, Priority . â â. .. ( ).
,
ContextBlockDrawer 3. ContextBlockDrawer () BlockDrawer . BlockDrawer, , () DrawerProcessor, .
:
ContextBlockDrawer -> ( )-> BlockDrawer -> -> DrawerProcessor.
ââ.
3 ContextBlockDrawer â â. ( ) : â â:
- , ( - )
- , .
: , , â â:
//
// ( )
var ctxBlockDrawer = new ContextBlockDrawer();
ctxBlockDrawer.BlockDrawer = blockDrawer;
//
// ( )
public class ContextBlockDrawer<TDrawerContext> {
...
public void Draw(TDrawerContext drawerContext,
Action<string, bool> onBlockDraw) {
...
var blockDrawer = ServiceLocator.Get<BlockDrawer>();
...
}
}
//
BlockDrawer (), ContextBlockDrawer BlockDrawer ( ):
public class ContextBlockDrawer<TDrawerContext> {
readonly IReadOnlyCollection<IContextDrawerBlock<TDrawerContext>> _BlockDrawers;
readonly BlockDrawer _Drawer;
public ContextBlockDrawer(
IReadOnlyCollection<IContextDrawerBlock<TDrawerContext>> blockDrawers) {
//
var drawer = new DrawerProcessor();
_Drawer = new BlockDrawer(drawer);
...
}
ContextBlockDrawer BlockDrawer : ContextBlockDrawer BlockDrawer, BlockDrawer. BlockDrawer( DrawerProcessor). .. , .
ASCII , - .
y x ContextBlockDrawer , :
public interface IContextDrawerBlock<TDrawerContext> {
int Priority { get; }
DrawerBlock Draw(int row, int blockIndex, TDrawerContext context);
}
Draw row blockIndex. . y :
public interface IartesianDrawerBlock<TDrawerContext> {
int Priority { get; }
DrawerBlock Draw(float x, float y, TDrawerContext context);
}
, :
class LineDrawer : IartesianDrawerBlock<artesianDrawerContext> {
public int Priority => 40;
public DrawerBlock Draw(float x, float y,
artesianDrawerContext context) {
var y1 = x; // y=x
// y1 y
// (c )
if (Math.Abs(y1 -y) <= context.Rounding)
return Block.Continue("#");
return null;
}
}
IartesianDrawerBlock ContextBlockDrawer. , âDraw(int row, int blockIndex, TDrawerContext context)â âDrawerBlock Draw(float x, float y, TDrawerContext context)â:
public class artesianDrawerAdapter<TDrawerContext> :
IContextDrawerBlock<TDrawerContext>
where TDrawerContext : IartesianDrawerAdapterContext {
readonly IartesianDrawerBlock<TDrawerContext> _cartesianDrawer;
public artesianDrawerAdapter(
IartesianDrawerBlock<TDrawerContext> cartesianDrawer) {
_cartesianDrawer = cartesianDrawer ?? throw ...
}
public int Priority => _cartesianDrawer.Priority;
public DrawerBlock Draw(int row, int blockIndex, TDrawerContext context) {
float x = blockIndex / context.Scale + context.XMin;
float y = context.YMax - row / context.Scale;
return _cartesianDrawer.Draw(x, y, context);
}
}
public interface IartesianDrawerAdapterContext {
public float Scale { get; }
public float XMin { get; }
public float YMax { get; }
}
artesianDrawerAdapter - :
// ctxBlockDrawer
var drawer = new DrawerProcessor();
var blockDrawer = new BlockDrawer(drawer);
var blockDrawers = new IartesianDrawerBlock<artesianDrawerContext>[] {
new EndDrawer(),
new EndLineDrawer(),
new LineDrawer(),
new EmptyDrawer()
}
.Select(dd =>
//
new artesianDrawerAdapter<artesianDrawerContext>(dd))
.ToArray();
var ctxBlockDrawer = new ContextBlockDrawer<artesianDrawerContext>(
blockDrawer,
blockDrawers);
// ctxBlockDrawer
ctxBlockDrawer.Draw(new artesianDrawerContext {
XMin = -2,
XMax = 30,
YMin = -2,
YMax = 8,
Scale = 5,
Rounding = 0.1F
},
(blockStr, isEnd) => Console.Write(blockStr));
: IContextDrawerBlock IartesianDrawerBlock ââ - artesianDrawerAdapter.
:
//
...
var ctxBlockDrawer = ...
var asciiDrawer =
new AsciiDrawer<artesianDrawerContext>(ctxBlockDrawer);
//
asciiDrawer
//
.OnBlockDraw((blockStr, isEnd) => Console.Write(blockStr))
.Draw(new artesianDrawerContext {
XMin = -2,
XMax = 30,
...
});
// 4. AsciiDrawer.
AsciiDrawer:
public class AsciiDrawer<TDrawerContext> {
readonly ContextBlockDrawer<TDrawerContext> _ContextBlockDrawer;
readonly Action<string, bool> _onBlockDraw;
public AsciiDrawer(
ContextBlockDrawer<TDrawerContext> contextBlockDrawer,
Action<string, bool> onBlockDraw = null) {
_ContextBlockDrawer = contextBlockDrawer ?? throw ...
_onBlockDraw = onBlockDraw;
}
public AsciiDrawer<TDrawerContext> OnBlockDraw(
Action<string, bool> onBlockDraw) {
//
// this (return this)
return new AsciiDrawer<TDrawerContext>(
_ContextBlockDrawer,
onBlockDraw);
}
public void Draw(TDrawerContext context) {
if (_onBlockDraw == null)
throw new InvalidOperationException("Use .OnBlockDraw to set up draw output");
_ContextBlockDrawer.Draw(context, _onBlockDraw);
}
}
: AsciiDrawer ââ - , . OnBlockDraw ( this). ââ .
SingleInstance
4 , ââ, IoC . AsciiDrawer.
Les objets ASCII du peintre ne stockent pas d'Ă©tats, ils sont Ă©galement «immuables», ce qui signifie que vous pouvez utiliser en toute sĂ©curitĂ© les mĂȘmes instances Ă diffĂ©rents endroits. L'inclusion de nos objets peut ĂȘtre enregistrĂ©e dans le conteneur IoC en tant que SingleInstance.
En conséquence, dans la démo de Blazor WebAssembly , cliquez sur le bouton Exécuter, le code suivant:
var res = new StringBuilder();
AsciiDrw
.OnBlockDraw((blockStr, isEnd) => {
res.Append(blockStr);
if (isEnd)
// UI
Res = res.ToString();
})
.Draw(new FuncsDrawerContext {
//
Rounding = Rounding,
Scale = Scale,
XMin = Xmin,
XMax = Xmax,
YMin = Ymin,
YMax = Ymax,
// y x
Functions = funcs
});
La démo utilise les blocs suivants:
new EndDrawer(),
new EndLineDrawer(),
new FuncsDrawer(), //
new XAxisDrawer(), // X
new YAxisDrawer(), // Y
new EmptyDrawer()
Vous pouvez également penser à :
un bloc qui peint la zone sous le graphique,
un bloc qui affiche une échelle sur les axes,
bloc qui signe les points d'intersection des graphiques.
Conclusion
Comme vous pouvez le voir, mĂȘme un problĂšme scolaire peut ĂȘtre sĂ©rieusement confondu - l'essentiel est de connaĂźtre les principes et les schĂ©mas.