Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/Libraries/CoreNodes/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,15 @@ public static IList Sort(IEnumerable<object> list)
[IsVisibleInDynamoLibrary(true)]
public static object MinimumItem(IEnumerable<object> list)
{
return list.Min<object, object>(DoubleConverter);
var comparer = new ObjectComparer();
object min = null;
foreach (var item in list)
{
Comment on lines 378 to +383
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MinimumItem/MaximumItem now iterate with foreach (var item in list) but don't guard against list == null. If list is null this will throw NullReferenceException, whereas the previous LINQ implementation would throw an ArgumentNullException (and matches other LINQ-based nodes). Add an explicit if (list == null) throw new ArgumentNullException(nameof(list)); (or return null if that's the intended node contract) to avoid the regression.

Copilot uses AI. Check for mistakes.
if (item == null) continue;
if (min == null || comparer.Compare(item, min) < 0)
min = item;
Comment on lines +382 to +386
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MinimumItem skips null entries (if (item == null) continue;). Previously, the LINQ-based implementation (Min(... DoubleConverter)) would treat a null projected value as the minimum and return null when any nulls are present in the sequence. This change can break graphs that relied on null propagating as the minimum. Either preserve the old semantics (return null when any element is null) or update the documented/expected behavior and add tests covering null-containing lists.

Suggested change
foreach (var item in list)
{
if (item == null) continue;
if (min == null || comparer.Compare(item, min) < 0)
min = item;
var hasMin = false;
foreach (var item in list)
{
if (item == null)
return null;
if (!hasMin || comparer.Compare(item, min) < 0)
{
min = item;
hasMin = true;
}

Copilot uses AI. Check for mistakes.
}
Comment on lines +382 to +387
return min;
Comment on lines +380 to +388
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new loop returns null for an empty list (because min/max never gets assigned). The previous LINQ implementation (Enumerable.Min/Max) throws InvalidOperationException for empty sequences, so this is a behavioral change. If graphs/tests rely on the exception behavior, consider explicitly detecting empties and matching the prior behavior (or document/test the new null return contract).

Copilot uses AI. Check for mistakes.
}

/// <summary>
Expand All @@ -389,7 +397,15 @@ public static object MinimumItem(IEnumerable<object> list)
[IsVisibleInDynamoLibrary(true)]
public static object MaximumItem(IEnumerable<object> list)
{
return list.Max<object, object>(DoubleConverter);
var comparer = new ObjectComparer();
object max = null;
foreach (var item in list)
{
if (item == null) continue;
if (max == null || comparer.Compare(item, max) > 0)
max = item;
}
Comment on lines +402 to +407
return max;
}

/// <summary>
Expand Down
36 changes: 36 additions & 0 deletions test/Libraries/CoreNodesTests/ListTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,42 @@ public static void ListMaximumValueMixed()
Assert.AreEqual(66, List.MaximumItem(new List<object> { 8.223, 4, 0.64, 66, 10.2 }));
}

[Test]
[Category("UnitTests")]
public static void ListMaximumItemPreservesInt64Type()
{
var result = List.MaximumItem(new List<object> { 8L, 4L, 0L, 66L, 10L });
Assert.IsInstanceOf<long>(result);
Assert.AreEqual(66L, result);
}

[Test]
[Category("UnitTests")]
public static void ListMinimumItemPreservesInt64Type()
{
var result = List.MinimumItem(new List<object> { 8L, 4L, 0L, 66L, 10L });
Assert.IsInstanceOf<long>(result);
Assert.AreEqual(0L, result);
}

[Test]
[Category("UnitTests")]
public static void ListMaximumItemPreservesIntType()
{
var result = List.MaximumItem(new List<object> { 8, 4, 0, 66, 10 });
Assert.IsInstanceOf<int>(result);
Assert.AreEqual(66, result);
}

[Test]
[Category("UnitTests")]
public static void ListMinimumItemPreservesIntType()
{
var result = List.MinimumItem(new List<object> { 8, 4, 0, 66, 10 });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when there is a mixed list of doubles and ints?

Assert.IsInstanceOf<int>(result);
Assert.AreEqual(0, result);
}

[Test]
[Category("UnitTests")]
public static void FilterListByMask()
Expand Down
Loading