using System.Collections.Generic;
public static (T? left, T? right) Fork<T>(IEnumerable<T?> source,
IComparer<T>? comparer = default) {
ArgumentNullException.ThrowIfNull(source);
comparer ??= Comparer<T>.Default;
ArgumentNullException.ThrowIfNull(comparer);
T? secondRight = default;
var hasSecondLeft = false;
var hasSecondRight = false;
foreach (var item in source) {
var compare = comparer.Compare(item, target);
if (!hasRight || comparer.Compare(item, right) <= 0) {
(hasSecondRight, hasRight) = (hasRight, true);
(secondRight, right) = (right, item);
else if (!hasSecondRight || comparer.Compare(item, secondRight) <= 0) {
if (!hasLeft || comparer.Compare(item, left) >= 0) {
(hasSecondLeft, hasLeft) = (hasLeft, true);
(secondLeft, left) = (left, item);
else if (!hasSecondLeft || comparer.Compare(item, secondLeft) <= 0) {
return hasLeft && hasRight ? (left, right)
: hasLeft ? (secondLeft, left)
private static (string prevValue, string nextValue) FindClosestValues(double valueToFind,
IEnumerable<(double time, string value, bool flag)> values) {
var comparer = Comparer<(double time, string value, bool flag)>
.Create((left, right) => left.time.CompareTo(right.time));
var result = Fork(values.Where(item => item.flag), (valueToFind, "", true), comparer);
return (result.left.Item2, result.right.Item2);
public static void Main() {
var listOfDoubleValues = new List<(double time, string value, bool flag)> {
var testDataWithExpectedValues = new List<(double value, string expectedPrevValue, string expectedNextValue)> {
var actual = testDataWithExpectedValues
.Select(item => $"{item.value, 3} : {FindClosestValues(item.value, listOfDoubleValues)} expected ({item.expectedPrevValue}, {item.expectedNextValue})");
Console.WriteLine(string.Join(Environment.NewLine, actual));