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). .. , .
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.