trackler 2.0.5.14 → 2.0.5.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/perfect-numbers/metadata.yml +1 -1
  3. data/lib/trackler/version.rb +1 -1
  4. data/tracks/csharp/config.json +17 -0
  5. data/tracks/csharp/exercises/exercises.csproj +1 -1
  6. data/tracks/csharp/exercises/react/Example.cs +124 -0
  7. data/tracks/csharp/exercises/react/HINTS.md +3 -0
  8. data/tracks/csharp/exercises/react/ReactTest.cs +121 -0
  9. data/tracks/csharp/exercises/tree-building/Example.cs +73 -0
  10. data/tracks/csharp/exercises/tree-building/TreeBuilding.cs +67 -0
  11. data/tracks/csharp/exercises/tree-building/TreeBuildingTest.cs +228 -0
  12. data/tracks/ecmascript/exercises/accumulate/package.json +1 -1
  13. data/tracks/ecmascript/exercises/acronym/package.json +1 -1
  14. data/tracks/ecmascript/exercises/all-your-base/package.json +1 -1
  15. data/tracks/ecmascript/exercises/allergies/package.json +1 -1
  16. data/tracks/ecmascript/exercises/anagram/package.json +1 -1
  17. data/tracks/ecmascript/exercises/atbash-cipher/package.json +1 -1
  18. data/tracks/ecmascript/exercises/beer-song/package.json +1 -1
  19. data/tracks/ecmascript/exercises/binary-search-tree/package.json +1 -1
  20. data/tracks/ecmascript/exercises/binary-search/package.json +1 -1
  21. data/tracks/ecmascript/exercises/binary/package.json +1 -1
  22. data/tracks/ecmascript/exercises/bob/package.json +1 -1
  23. data/tracks/ecmascript/exercises/bracket-push/package.json +1 -1
  24. data/tracks/ecmascript/exercises/circular-buffer/package.json +1 -1
  25. data/tracks/ecmascript/exercises/clock/package.json +1 -1
  26. data/tracks/ecmascript/exercises/crypto-square/package.json +1 -1
  27. data/tracks/ecmascript/exercises/custom-set/package.json +1 -1
  28. data/tracks/ecmascript/exercises/diamond/package.json +1 -1
  29. data/tracks/ecmascript/exercises/difference-of-squares/package.json +1 -1
  30. data/tracks/ecmascript/exercises/etl/package.json +1 -1
  31. data/tracks/ecmascript/exercises/food-chain/package.json +1 -1
  32. data/tracks/ecmascript/exercises/gigasecond/package.json +1 -1
  33. data/tracks/ecmascript/exercises/grade-school/package.json +1 -1
  34. data/tracks/ecmascript/exercises/grains/package.json +1 -1
  35. data/tracks/ecmascript/exercises/hamming/package.json +1 -1
  36. data/tracks/ecmascript/exercises/hello-world/package.json +1 -1
  37. data/tracks/ecmascript/exercises/hexadecimal/package.json +1 -1
  38. data/tracks/ecmascript/exercises/isogram/package.json +1 -1
  39. data/tracks/ecmascript/exercises/kindergarten-garden/package.json +1 -1
  40. data/tracks/ecmascript/exercises/largest-series-product/package.json +1 -1
  41. data/tracks/ecmascript/exercises/leap/package.json +1 -1
  42. data/tracks/ecmascript/exercises/linked-list/package.json +1 -1
  43. data/tracks/ecmascript/exercises/luhn/package.json +1 -1
  44. data/tracks/ecmascript/exercises/matrix/package.json +1 -1
  45. data/tracks/ecmascript/exercises/meetup/package.json +1 -1
  46. data/tracks/ecmascript/exercises/nth-prime/package.json +1 -1
  47. data/tracks/ecmascript/exercises/ocr-numbers/package.json +1 -1
  48. data/tracks/ecmascript/exercises/octal/package.json +1 -1
  49. data/tracks/ecmascript/exercises/palindrome-products/package.json +1 -1
  50. data/tracks/ecmascript/exercises/pangram/package.json +1 -1
  51. data/tracks/ecmascript/exercises/pascals-triangle/package.json +1 -1
  52. data/tracks/ecmascript/exercises/phone-number/package.json +1 -1
  53. data/tracks/ecmascript/exercises/pig-latin/package.json +1 -1
  54. data/tracks/ecmascript/exercises/prime-factors/package.json +1 -1
  55. data/tracks/ecmascript/exercises/pythagorean-triplet/package.json +1 -1
  56. data/tracks/ecmascript/exercises/queen-attack/package.json +1 -1
  57. data/tracks/ecmascript/exercises/raindrops/package.json +1 -1
  58. data/tracks/ecmascript/exercises/rna-transcription/package.json +1 -1
  59. data/tracks/ecmascript/exercises/robot-name/package.json +1 -1
  60. data/tracks/ecmascript/exercises/robot-simulator/package.json +1 -1
  61. data/tracks/ecmascript/exercises/roman-numerals/package.json +1 -1
  62. data/tracks/ecmascript/exercises/saddle-points/package.json +1 -1
  63. data/tracks/ecmascript/exercises/say/package.json +1 -1
  64. data/tracks/ecmascript/exercises/scrabble-score/package.json +1 -1
  65. data/tracks/ecmascript/exercises/secret-handshake/package.json +1 -1
  66. data/tracks/ecmascript/exercises/series/package.json +1 -1
  67. data/tracks/ecmascript/exercises/sieve/package.json +1 -1
  68. data/tracks/ecmascript/exercises/simple-cipher/package.json +1 -1
  69. data/tracks/ecmascript/exercises/space-age/package.json +1 -1
  70. data/tracks/ecmascript/exercises/strain/package.json +1 -1
  71. data/tracks/ecmascript/exercises/sum-of-multiples/package.json +1 -1
  72. data/tracks/ecmascript/exercises/triangle/package.json +1 -1
  73. data/tracks/ecmascript/exercises/trinary/package.json +1 -1
  74. data/tracks/ecmascript/exercises/two-bucket/package.json +1 -1
  75. data/tracks/ecmascript/exercises/word-count/package.json +1 -1
  76. data/tracks/ecmascript/exercises/wordy/package.json +1 -1
  77. data/tracks/ecmascript/package.json +1 -1
  78. data/tracks/elixir/docs/ABOUT.md +1 -1
  79. data/tracks/haskell/config.json +6 -0
  80. data/tracks/haskell/exercises/run-length-encoding/examples/success-standard/package.yaml +16 -0
  81. data/tracks/haskell/exercises/run-length-encoding/examples/success-standard/src/RunLength.hs +21 -0
  82. data/tracks/haskell/exercises/run-length-encoding/package.yaml +19 -0
  83. data/tracks/haskell/exercises/run-length-encoding/src/RunLength.hs +7 -0
  84. data/tracks/haskell/exercises/run-length-encoding/stack.yaml +1 -0
  85. data/tracks/haskell/exercises/run-length-encoding/test/Tests.hs +75 -0
  86. data/tracks/javascript/config.json +8 -1
  87. data/tracks/javascript/exercises/run-length-encoding/example.js +11 -0
  88. data/tracks/javascript/exercises/run-length-encoding/run-length-encoding.spec.js +41 -0
  89. data/tracks/pascal/.gitignore +2 -0
  90. data/tracks/pascal/config.json +8 -8
  91. data/tracks/pascal/exercises/{Hello-World → hello-world}/uHelloWorldExample.pas +0 -0
  92. data/tracks/pascal/exercises/{Hello-World → hello-world}/uTestHelloWorld.pas +0 -0
  93. metadata +18 -36
  94. data/tracks/pascal/exercises/Hello-World/TestHelloWorld.dpr +0 -60
  95. data/tracks/pascal/exercises/Hello-World/TestHelloWorld.dproj +0 -176
  96. data/tracks/pascal/exercises/allergies/AllergyTests.dpr +0 -60
  97. data/tracks/pascal/exercises/allergies/AllergyTests.dproj +0 -176
  98. data/tracks/pascal/exercises/bank-account/BankAccountTests.dpr +0 -60
  99. data/tracks/pascal/exercises/bank-account/BankAccountTests.dproj +0 -176
  100. data/tracks/pascal/exercises/beer-song/BeerSongTests.dpr +0 -60
  101. data/tracks/pascal/exercises/beer-song/BeerSongTests.dproj +0 -176
  102. data/tracks/pascal/exercises/binary-search/BinarySearchTest.dpr +0 -60
  103. data/tracks/pascal/exercises/binary-search/BinarySearchTest.dproj +0 -176
  104. data/tracks/pascal/exercises/bob/BobTests.dpr +0 -60
  105. data/tracks/pascal/exercises/bob/BobTests.dproj +0 -176
  106. data/tracks/pascal/exercises/book-store/BookStoreTests.dpr +0 -60
  107. data/tracks/pascal/exercises/book-store/BookStoreTests.dproj +0 -176
  108. data/tracks/pascal/exercises/bowling/BowlingTests.dpr +0 -60
  109. data/tracks/pascal/exercises/bowling/BowlingTests.dproj +0 -176
  110. data/tracks/pascal/exercises/circular-buffer/CircularBufferTests.dpr +0 -60
  111. data/tracks/pascal/exercises/circular-buffer/CircularBufferTests.dproj +0 -176
  112. data/tracks/pascal/exercises/clock/ClockTest.dpr +0 -60
  113. data/tracks/pascal/exercises/clock/ClockTest.dproj +0 -176
  114. data/tracks/pascal/exercises/etl/ETLtests.dpr +0 -60
  115. data/tracks/pascal/exercises/etl/ETLtests.dproj +0 -176
  116. data/tracks/pascal/exercises/hamming/Hamming.dpr +0 -60
  117. data/tracks/pascal/exercises/hamming/Hamming.dproj +0 -176
  118. data/tracks/pascal/exercises/leap/LeapTest.dpr +0 -60
  119. data/tracks/pascal/exercises/leap/LeapTest.dproj +0 -176
  120. data/tracks/pascal/exercises/nucleotide-count/NucleotideCountTest.dpr +0 -60
  121. data/tracks/pascal/exercises/nucleotide-count/NucleotideCountTest.dproj +0 -176
  122. data/tracks/pascal/exercises/perfect-numbers/PerfectNumbersTest.dpr +0 -60
  123. data/tracks/pascal/exercises/perfect-numbers/PerfectNumbersTest.dproj +0 -176
  124. data/tracks/pascal/exercises/phone-number/PhoneNumberTests.dpr +0 -60
  125. data/tracks/pascal/exercises/phone-number/PhoneNumberTests.dproj +0 -176
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec7742a72a8b9cb40403f1fa21b731c45a0e949c
4
- data.tar.gz: 659146e560273f0e3fc0e1c1830d46d63e4c6c53
3
+ metadata.gz: 640bf7c491e8a9613de8e88ee23185a2ccfe7114
4
+ data.tar.gz: dc1a5b2fd961f1bea01631d313ce1ebf9ef8497f
5
5
  SHA512:
6
- metadata.gz: 8209ff1442ff1dd4a05810ca4d608e3bcc16e121e628d7dfde8611b6baf0239da3e031062c4ecdd263d4a142a993686e42161f650db166b7a8497c1a3ceeb442
7
- data.tar.gz: 20053304e9f4973b491bc7cc7ee2dcb1a671699dedbab5dbcd232c7ba83f2efcc3e1269fa3de6cd7b7c3617b37cbb8d73338ebebd70ed64e199ccfd5ab58d811
6
+ metadata.gz: 90d0a3630526b437476b6a2a3c08b9a4b538550972b606f503ad8092b344e668d5642aa52d02ad5b93f99eb6bd6c17fdd69f271274f0da60c77b2482f5103b65
7
+ data.tar.gz: 77cb6e64a0f978ee41e62bb23d86b49c0ed9cdaa789f5cfab0167735ab9058138da1b5326992ac87f6afc0cd03fd0790f9ce2c2066aee028c6512bfb0d790c6f
@@ -1,4 +1,4 @@
1
1
  ---
2
- blurb: "The Greek mathematician Nicomachus devised a classification scheme for natural numbers."
2
+ blurb: "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for natural numbers."
3
3
  source: "Taken from Chapter 2 of Functional Thinking by Neal Ford."
4
4
  source_url: "http://shop.oreilly.com/product/0636920029687.do"
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.5.14"
2
+ VERSION = "2.0.5.15"
3
3
  end
@@ -486,6 +486,14 @@
486
486
  "Lists"
487
487
  ]
488
488
  },
489
+ {
490
+ "slug": "tree-building",
491
+ "difficulty": 5,
492
+ "topics": [
493
+ "Trees",
494
+ "Refactoring"
495
+ ]
496
+ },
489
497
  {
490
498
  "slug": "scale-generator",
491
499
  "difficulty": 5,
@@ -739,6 +747,15 @@
739
747
  "Text formatting"
740
748
  ]
741
749
  },
750
+ {
751
+ "slug": "react",
752
+ "difficulty": 9,
753
+ "topics": [
754
+ "Reactive programming",
755
+ "Classes",
756
+ "Events"
757
+ ]
758
+ },
742
759
  {
743
760
  "slug": "variable-length-quantity",
744
761
  "difficulty": 9,
@@ -38,7 +38,7 @@
38
38
  <Reference Include="Microsoft.CSharp" />
39
39
  </ItemGroup>
40
40
  <ItemGroup>
41
- <Compile Include="**\*.cs" Exclude="sgf-parsing\SgfParsing.cs;markdown\Markdown.cs" />
41
+ <Compile Include="**\*.cs" Exclude="sgf-parsing\SgfParsing.cs;markdown\Markdown.cs;tree-building\TreeBuilding.cs" />
42
42
  </ItemGroup>
43
43
  <ItemGroup>
44
44
  <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
@@ -0,0 +1,124 @@
1
+ using System;
2
+ using System.Collections;
3
+ using System.Collections.Generic;
4
+ using System.Linq;
5
+
6
+ public delegate void ChangedEventHandler(object sender, int value);
7
+
8
+ public class Reactor
9
+ {
10
+ private readonly Dictionary<int, Cell> cells = new Dictionary<int, Cell>();
11
+
12
+ public InputCell CreateInputCell(int value)
13
+ {
14
+ var inputCell = new InputCell(cells.Count, value);
15
+ inputCell.Changed += CellChanged;
16
+
17
+ cells[inputCell.Id] = inputCell;
18
+
19
+ return inputCell;
20
+ }
21
+
22
+ public ComputeCell CreateComputeCell(IEnumerable<Cell> producers, Func<int[], int> compute)
23
+ {
24
+ var computeCell = new ComputeCell(cells.Count, producers, compute);
25
+ cells[computeCell.Id] = computeCell;
26
+
27
+ return computeCell;
28
+ }
29
+
30
+ private void CellChanged(object sender, int value)
31
+ {
32
+ var cell = (Cell)sender;
33
+ var consumers = new BitArray(cells.Count);
34
+
35
+ foreach (var consumer in cell.Consumers)
36
+ consumers.Set(consumer.Id, true);
37
+
38
+ for (var id = cell.Id + 1; id < cells.Count; id++)
39
+ {
40
+ if (!consumers.Get(id))
41
+ continue;
42
+
43
+ var consumer = (ComputeCell)cells[id];
44
+ consumer.Recompute();
45
+
46
+ foreach (var transitiveConsumer in consumer.Consumers)
47
+ consumers.Set(transitiveConsumer.Id, true);
48
+ }
49
+ }
50
+ }
51
+
52
+ public abstract class Cell
53
+ {
54
+ public Cell(int id)
55
+ {
56
+ Id = id;
57
+ Consumers = new List<Cell>();
58
+ }
59
+
60
+ public int Id { get; }
61
+ public List<Cell> Consumers { get; }
62
+
63
+ public abstract int Value { get; set; }
64
+ public abstract event ChangedEventHandler Changed;
65
+ }
66
+
67
+ public class InputCell : Cell
68
+ {
69
+ private int _value;
70
+
71
+ public InputCell(int id, int value) : base(id)
72
+ {
73
+ _value = value;
74
+ }
75
+
76
+ public override event ChangedEventHandler Changed;
77
+
78
+ public override int Value
79
+ {
80
+ get
81
+ {
82
+ return _value;
83
+ }
84
+ set
85
+ {
86
+ if (_value == value)
87
+ return;
88
+
89
+ _value = value;
90
+ Changed?.Invoke(this, _value);
91
+ }
92
+ }
93
+ }
94
+
95
+ public class ComputeCell : Cell
96
+ {
97
+ private readonly IEnumerable<Cell> producers;
98
+ private readonly Func<int[], int> compute;
99
+
100
+ public ComputeCell(int id, IEnumerable<Cell> producers, Func<int[], int> compute) : base(id)
101
+ {
102
+ this.producers = producers;
103
+ this.compute = compute;
104
+
105
+ foreach (var producer in producers)
106
+ producer.Consumers.Add(this);
107
+
108
+ Recompute();
109
+ }
110
+
111
+ public override int Value { get; set; }
112
+ public override event ChangedEventHandler Changed;
113
+
114
+ public void Recompute()
115
+ {
116
+ var updatedValue = compute(producers.Select(producer => producer.Value).ToArray());
117
+
118
+ if (updatedValue == Value)
119
+ return;
120
+
121
+ Value = updatedValue;
122
+ Changed?.Invoke(this, updatedValue);
123
+ }
124
+ }
@@ -0,0 +1,3 @@
1
+ ## Hints
2
+ In this exercise the following C# feature is used:
3
+ - [Events](https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx).
@@ -0,0 +1,121 @@
1
+ using NUnit.Framework;
2
+ using System.Collections.Generic;
3
+
4
+ public class ReactTest
5
+ {
6
+ [Test]
7
+ public void Setting_the_value_of_an_input_cell_changes_the_observable_value()
8
+ {
9
+ var reactor = new Reactor();
10
+ var inputCell1 = reactor.CreateInputCell(1);
11
+
12
+ Assert.That(inputCell1.Value, Is.EqualTo(1));
13
+ inputCell1.Value = 2;
14
+ Assert.That(inputCell1.Value, Is.EqualTo(2));
15
+ }
16
+
17
+ [Ignore("Remove to run test")]
18
+ [Test]
19
+ public void The_value_of_a_compute_is_determined_by_the_value_of_the_dependencies()
20
+ {
21
+ var reactor = new Reactor();
22
+ var inputCell1 = reactor.CreateInputCell(1);
23
+ var computeCell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] + 1);
24
+
25
+ Assert.That(computeCell1.Value, Is.EqualTo(2));
26
+ inputCell1.Value = 2;
27
+ Assert.That(computeCell1.Value, Is.EqualTo(3));
28
+ }
29
+
30
+ [Ignore("Remove to run test")]
31
+ [Test]
32
+ public void Compute_cells_can_depend_on_other_compute_cells()
33
+ {
34
+ var reactor = new Reactor();
35
+ var inputCell1 = reactor.CreateInputCell(1);
36
+ var computeCell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] + 1);
37
+ var computeCell2 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] - 1);
38
+ var computeCell3 = reactor.CreateComputeCell(new[] { computeCell1, computeCell2 }, (values) => values[0] * values[1]);
39
+
40
+ Assert.That(computeCell3.Value, Is.EqualTo(0));
41
+ inputCell1.Value = 3;
42
+ Assert.That(computeCell3.Value, Is.EqualTo(8));
43
+ }
44
+
45
+ [Ignore("Remove to run test")]
46
+ [Test]
47
+ public void Compute_cells_can_have_callbacks()
48
+ {
49
+ var reactor = new Reactor();
50
+ var inputCell1 = reactor.CreateInputCell(1);
51
+ var computeCell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] + 1);
52
+ var observed = new List<int>();
53
+ computeCell1.Changed += (sender, value) => observed.Add(value);
54
+
55
+ Assert.That(observed, Is.Empty);
56
+ inputCell1.Value = 2;
57
+ Assert.That(observed, Is.EquivalentTo(new[] { 3 }));
58
+ }
59
+
60
+ [Ignore("Remove to run test")]
61
+ [Test]
62
+ public void Callbacks_only_trigger_on_change()
63
+ {
64
+ var reactor = new Reactor();
65
+ var inputCell1 = reactor.CreateInputCell(1);
66
+ var computecell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] > 2 ? values[0] + 1 : 2);
67
+ var observerCalled = 0;
68
+ computecell1.Changed += (sender, value) => observerCalled++;
69
+
70
+ inputCell1.Value = 1;
71
+ Assert.That(observerCalled, Is.EqualTo(0));
72
+ inputCell1.Value = 2;
73
+ Assert.That(observerCalled, Is.EqualTo(0));
74
+ inputCell1.Value = 3;
75
+ Assert.That(observerCalled, Is.EqualTo(1));
76
+ }
77
+
78
+ [Ignore("Remove to run test")]
79
+ [Test]
80
+ public void Callbacks_can_be_removed()
81
+ {
82
+ var reactor = new Reactor();
83
+ var inputCell1 = reactor.CreateInputCell(1);
84
+ var computeCell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] + 1);
85
+ var observed1 = new List<int>();
86
+ var observed2 = new List<int>();
87
+
88
+ ChangedEventHandler changedHandler1 = (object sender, int value) => observed1.Add(value);
89
+ ChangedEventHandler changedHandler2 = (object sender, int value) => observed2.Add(value);
90
+
91
+ computeCell1.Changed += changedHandler1;
92
+ computeCell1.Changed += changedHandler2;
93
+
94
+ inputCell1.Value = 2;
95
+ Assert.That(observed1, Is.EquivalentTo(new[] { 3 }));
96
+ Assert.That(observed2, Is.EquivalentTo(new[] { 3 }));
97
+
98
+ computeCell1.Changed -= changedHandler1;
99
+ inputCell1.Value = 3;
100
+ Assert.That(observed1, Is.EquivalentTo(new[] { 3 }));
101
+ Assert.That(observed2, Is.EquivalentTo(new[] { 3, 4 }));
102
+ }
103
+
104
+ [Ignore("Remove to run test")]
105
+ [Test]
106
+ public void Callbacks_should_only_be_called_once_even_if_multiple_dependencies_have_changed()
107
+ {
108
+ var reactor = new Reactor();
109
+ var inputCell1 = reactor.CreateInputCell(1);
110
+ var computeCell1 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] + 1);
111
+ var computeCell2 = reactor.CreateComputeCell(new[] { inputCell1 }, (values) => values[0] - 1);
112
+ var computeCell3 = reactor.CreateComputeCell(new[] { computeCell2 }, (values) => values[0] - 1);
113
+ var computeCell4 = reactor.CreateComputeCell(new[] { computeCell1, computeCell3 }, (values) => values[0] * values[1]);
114
+
115
+ var changed4 = 0;
116
+ computeCell4.Changed += (sender, value) => changed4++;
117
+
118
+ inputCell1.Value = 3;
119
+ Assert.That(changed4, Is.EqualTo(1));
120
+ }
121
+ }
@@ -0,0 +1,73 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Linq;
4
+
5
+ public class TreeBuildingRecord
6
+ {
7
+ private const int RootRecordId = 0;
8
+
9
+ public int ParentId { get; set; }
10
+ public int RecordId { get; set; }
11
+
12
+ public bool IsRoot => RecordId == RootRecordId;
13
+ }
14
+
15
+ public class Tree
16
+ {
17
+ public Tree(int id)
18
+ {
19
+ Id = id;
20
+ Children = new List<Tree>();
21
+ }
22
+
23
+ public int Id { get; }
24
+
25
+ public List<Tree> Children { get; }
26
+
27
+ public bool IsLeaf => Children.Count == 0;
28
+ }
29
+
30
+ public static class TreeBuilder
31
+ {
32
+ private const int RootRecordId = 0;
33
+
34
+ public static Tree BuildTree(IEnumerable<TreeBuildingRecord> records)
35
+ {
36
+ var orderedRecords = GetOrderedRecords(records);
37
+
38
+ if (orderedRecords.Count == 0)
39
+ throw new ArgumentException();
40
+
41
+ var nodes = new Dictionary<int, Tree>();
42
+ var previousRecordId = -1;
43
+
44
+ foreach (var record in orderedRecords)
45
+ {
46
+ ValidateRecord(record, previousRecordId);
47
+
48
+ nodes[record.RecordId] = new Tree(record.RecordId);
49
+
50
+ if (!record.IsRoot)
51
+ nodes[record.ParentId].Children.Add(nodes[record.RecordId]);
52
+
53
+ previousRecordId++;
54
+ }
55
+
56
+ return nodes[RootRecordId];
57
+ }
58
+
59
+ private static void ValidateRecord(TreeBuildingRecord record, int previousRecordId)
60
+ {
61
+ if (record.IsRoot && record.ParentId != RootRecordId)
62
+ throw new ArgumentException();
63
+ else if (!record.IsRoot && record.ParentId >= record.RecordId)
64
+ throw new ArgumentException();
65
+ else if (!record.IsRoot && record.RecordId != previousRecordId + 1)
66
+ throw new ArgumentException();
67
+ }
68
+
69
+ private static List<TreeBuildingRecord> GetOrderedRecords(IEnumerable<TreeBuildingRecord> records)
70
+ {
71
+ return records.OrderBy(record => record.RecordId).ToList();
72
+ }
73
+ }
@@ -0,0 +1,67 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Linq;
4
+
5
+ public class TreeBuildingRecord
6
+ {
7
+ public int ParentId { get; set; }
8
+ public int RecordId { get; set; }
9
+ }
10
+
11
+ public class Tree
12
+ {
13
+ public int Id { get; set; }
14
+ public int ParentId { get; set; }
15
+
16
+ public List<Tree> Children { get; set; }
17
+
18
+ public bool IsLeaf => Children.Count == 0;
19
+ }
20
+
21
+ public static class TreeBuilder
22
+ {
23
+ public static Tree BuildTree(IEnumerable<TreeBuildingRecord> records)
24
+ {
25
+ var ordered = new SortedList<int, TreeBuildingRecord>();
26
+
27
+ foreach (var record in records)
28
+ {
29
+ ordered.Add(record.RecordId, record);
30
+ }
31
+
32
+ records = ordered.Values;
33
+
34
+ var trees = new List<Tree>();
35
+ var previousRecordId = -1;
36
+
37
+ foreach (var record in records)
38
+ {
39
+ var t = new Tree { Children = new List<Tree>(), Id = record.RecordId, ParentId = record.ParentId };
40
+ trees.Add(t);
41
+
42
+ if ((t.Id == 0 && t.ParentId != 0) ||
43
+ (t.Id != 0 && t.ParentId >= t.Id) ||
44
+ (t.Id != 0 && t.Id != previousRecordId + 1))
45
+ {
46
+ throw new ArgumentException();
47
+ }
48
+
49
+ ++previousRecordId;
50
+ }
51
+
52
+ if (trees.Count == 0)
53
+ {
54
+ throw new ArgumentException();
55
+ }
56
+
57
+ for (int i = 1; i < trees.Count; i++)
58
+ {
59
+ var t = trees.First(x => x.Id == i);
60
+ var parent = trees.First(x => x.Id == t.ParentId);
61
+ parent.Children.Add(t);
62
+ }
63
+
64
+ var r = trees.First(t => t.Id == 0);
65
+ return r;
66
+ }
67
+ }