Skip to content

Commit

Permalink
Merge pull request #52 from sharpcode-it/develop
Browse files Browse the repository at this point in the history
Develop into Master
  • Loading branch information
iscifoni authored Nov 25, 2024
2 parents 7ed0543 + 39e3df5 commit b1c69ba
Show file tree
Hide file tree
Showing 9 changed files with 549 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.5.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.5.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.6.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.6.3" />
</ItemGroup>

<ItemGroup>
Expand Down
48 changes: 48 additions & 0 deletions SharpHelpers/SharpHelpers/BooleanHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// (c) 2019 SharpCoding
// This code is licensed under MIT license (see LICENSE.txt for details)
using System;

namespace SharpCoding.SharpHelpers
{
public static class BooleanHelper
Expand Down Expand Up @@ -49,5 +51,51 @@ public static string ToStringValues(this bool? value, string trueValue, string f
{
return value.HasValue ? (value.Value ? trueValue : falseValue) : falseValue;
}

/// <summary>
/// Negates the instance boolean value.
/// </summary>
/// <param name="instance">The boolean value to negate.</param>
/// <returns>Returns the negated boolean value.</returns>
public static bool Not(this bool instance)
{
return !instance;
}

/// <summary>
/// Determines if the instance is true and executes the specified action if true.
/// </summary>
/// <param name="instance">The boolean value to evaluate.</param>
/// <param name="action">The action to execute if the boolean value is true.</param>
public static void IfTrue(this bool instance, Action action)
{
if (instance)
{
action?.Invoke();
}
}

/// <summary>
/// Determines if the instance is false and executes the specified action if false.
/// </summary>
/// <param name="instance">The boolean value to evaluate.</param>
/// <param name="action">The action to execute if the boolean value is false.</param>
public static void IfFalse(this bool instance, Action action)
{
if (!instance)
{
action?.Invoke();
}
}

/// <summary>
/// Returns the boolean value as an integer (1 for true, 0 for false).
/// </summary>
/// <param name="instance">The boolean value to convert.</param>
/// <returns>1 if true, 0 if false.</returns>
public static int ToInt(this bool instance)
{
return instance ? 1 : 0;
}
}
}
134 changes: 134 additions & 0 deletions SharpHelpers/SharpHelpers/DataTableHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;

namespace SharpCoding.SharpHelpers
Expand Down Expand Up @@ -51,6 +52,139 @@ public static DataTable SetColumnsOrder(this DataTable table, string[] columnNam
list.Add(objClass);
}
return list;
}

/// <summary>
/// Converts the DataTable to a CSV format string.
/// </summary>
/// <param name="table"></param>
/// <param name="delimiter"></param>
/// <returns></returns>
public static string ToCsv(this DataTable table, string delimiter = ",")
{
if (table == null) throw new ArgumentNullException(nameof(table));

var csv = new List<string>();
var headers = string.Join(delimiter, table.Columns.Cast<DataColumn>().Select(c => c.ColumnName));
csv.Add(headers);

foreach (DataRow row in table.Rows)
{
var line = string.Join(delimiter, row.ItemArray.Select(field => field?.ToString()));
csv.Add(line);
}
return string.Join(Environment.NewLine, csv);
}

/// <summary>
/// Adds a new column to the DataTable with the specified default value.
/// </summary>
/// <param name="table"></param>
/// <param name="columnName"></param>
/// <param name="defaultValue"></param>
/// <typeparam name="T"></typeparam>
public static void AddColumn<T>(this DataTable table, string columnName, T defaultValue = default)
{
if (table == null) throw new ArgumentNullException(nameof(table));

var column = new DataColumn(columnName, typeof(T)) { DefaultValue = defaultValue };
table.Columns.Add(column);
foreach (DataRow row in table.Rows)
{
row[columnName] = defaultValue;
}
}

/// <summary>
/// Merges multiple DataTables with the same schema into one.
/// </summary>
/// <param name="tables"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static DataTable MergeTables(IEnumerable<DataTable> tables)
{
if (tables == null) throw new ArgumentNullException(nameof(tables));

var resultTable = tables.First().Clone();
foreach (var table in tables)
{
if (!AreSchemasCompatible(resultTable, table))
throw new ArgumentException("Tables have incompatible schemas.");

foreach (DataRow row in table.Rows)
{
resultTable.ImportRow(row);
}
}
return resultTable;
}

private static bool AreSchemasCompatible(DataTable table1, DataTable table2)
{
if (table1.Columns.Count != table2.Columns.Count) return false;

for (int i = 0; i < table1.Columns.Count; i++)
{
if (table1.Columns[i].ColumnName != table2.Columns[i].ColumnName ||
table1.Columns[i].DataType != table2.Columns[i].DataType)
return false;
}
return true;
}

/// <summary>
/// Filters the rows in the DataTable based on a predicate.
/// </summary>
/// <param name="table"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static DataTable Filter(this DataTable table, Func<DataRow, bool> predicate)
{
if (table == null) throw new ArgumentNullException(nameof(table));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));

var filteredTable = table.Clone();
foreach (DataRow row in table.AsEnumerable().Where(predicate))
{
filteredTable.ImportRow(row);
}
return filteredTable;
}

/// <summary>
/// Checks if the DataTable is empty (contains no rows).
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
public static bool IsEmpty(this DataTable table)
{
if (table == null) throw new ArgumentNullException(nameof(table));

return table.Rows.Count == 0;
}

/// <summary>
/// Removes duplicate rows based on specified columns.
/// </summary>
/// <param name="table"></param>
/// <param name="columnNames"></param>
/// <returns></returns>
public static DataTable RemoveDuplicates(this DataTable table, params string[] columnNames)
{
if (table == null) throw new ArgumentNullException(nameof(table));

var distinctTable = table.Clone();
var uniqueRows = new HashSet<string>();

foreach (DataRow row in table.Rows)
{
var key = string.Join("|", columnNames.Select(c => row[c]?.ToString() ?? ""));
if (uniqueRows.Add(key))
{
distinctTable.ImportRow(row);
}
}
return distinctTable;
}
}
}
117 changes: 117 additions & 0 deletions SharpHelpers/SharpHelpers/EnumerableHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,122 @@ public static int Sum<T>(this IEnumerable<T> source, Func<T, int> selector)

return source.Select(selector).Sum();
}

/// <summary>
/// Returns the maximum element based on a given selector function.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="source"></param>
/// <param name="selector"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
where TKey : IComparable<TKey>
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));

return source.Aggregate((maxItem, nextItem) => selector(nextItem).CompareTo(selector(maxItem)) > 0 ? nextItem : maxItem);
}

/// <summary>
/// Returns the minimum element based on a given selector function.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TKey"></typeparam>
/// <param name="source"></param>
/// <param name="selector"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
where TKey : IComparable<TKey>
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (selector == null) throw new ArgumentNullException(nameof(selector));

return source.Aggregate((minItem, nextItem) => selector(nextItem).CompareTo(selector(minItem)) < 0 ? nextItem : minItem);
}

/// <summary>
/// Finds the index of the first element that satisfies a given predicate.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="predicate"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static int FindIndex<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));

int index = 0;
foreach (var item in source)
{
if (predicate(item)) return index;
index++;
}
return -1;
}

/// <summary>
/// Checks if the source contains any of the specified items.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="items"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static bool ContainsAny<T>(this IEnumerable<T> source, params T[] items)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (items == null) throw new ArgumentNullException(nameof(items));

var set = new HashSet<T>(items);
return source.Any(set.Contains);
}

/// <summary>
/// Checks if the source contains all of the specified items.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="items"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static bool ContainsAll<T>(this IEnumerable<T> source, params T[] items)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (items == null) throw new ArgumentNullException(nameof(items));

var set = new HashSet<T>(source);
return items.All(set.Contains);
}

/// <summary>
/// Returns the median of a sequence of numbers.
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static double Median(this IEnumerable<int> source)
{
if (source == null) throw new ArgumentNullException(nameof(source));

var sortedList = source.OrderBy(n => n).ToList();
int count = sortedList.Count;
if (count == 0)
throw new InvalidOperationException("The source sequence is empty.");

if (count % 2 == 0)
{
return (sortedList[count / 2 - 1] + sortedList[count / 2]) / 2.0;
}
else
{
return sortedList[count / 2];
}
}
}
}
Loading

0 comments on commit b1c69ba

Please sign in to comment.