Skip to content

Update assembly and package #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Nov 25, 2024
Merged
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
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
Loading