Last active
August 14, 2020 08:45
-
-
Save Protiguous/bbbce685f592fb7d80cec04ca7bdb28a to your computer and use it in GitHub Desktop.
Example to show adding items to a list and removing certain items.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Verified to run under .NET 5.0 Console Application. | |
namespace ConsoleApp1 { | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
using JetBrains.Annotations; | |
using Album = System.Collections.Generic.List<Music>; | |
//install the nuget package "JetBrains.Annotations" | |
public class Program { | |
public static void Main( [CanBeNull] String[] _ ) { | |
//starts here | |
RunProgram(); | |
//ends here. | |
static void RunProgram() { | |
TestCreateAddRemoveAndList(); //just showing off "local functions" | |
} | |
static void TestCreateAddRemoveAndList() { | |
//start a collection of music.. (the 50 is the optional "capacity", which is memory allocated for the list) | |
//if you know the max capacity ahead of time, your program won't allocate excessive memory. | |
var album = new Album( capacity: 50 ); | |
var addedAlbums = AddAlbums( album ); | |
Console.WriteLine( $"Created a collection of {addedAlbums} albums." ); | |
CheckMusic( album, "Test and write out our music collection before:" ); | |
//turns out you don't like foo's music | |
var totalRemoved = DontWantMusic( album, "foo" ); | |
Console.WriteLine( $"{totalRemoved} songs were removed." ); | |
CheckMusic( album, "Test and write out our music collection after:" ); | |
} | |
//just a local function | |
static void CheckMusic( Album album, String why ) { | |
if ( album == null ) { | |
throw new ArgumentNullException( nameof( album ) ); | |
} | |
Console.WriteLine( Environment.NewLine ); //redundant. just showing it's there. | |
if ( !String.IsNullOrEmpty( why ) ) { | |
Console.WriteLine( why ); | |
} | |
foreach ( var music in album ) { | |
Debug.Assert( music != null, nameof( music ) + " != null" ); | |
Console.WriteLine( $"The {nameof( music )} is by the {nameof( music.Artist )} \"{music.Artist}\" and has {music.Tracklist.Count} tracks." ); | |
} | |
} | |
static Int32 AddAlbums( Album album ) { | |
if ( album == null ) { | |
throw new ArgumentNullException( nameof( album ) ); | |
} | |
var rnd = new Random(); //just to create some random song lengths | |
Console.Write( "Adding music albums... " ); | |
var added = 0; | |
if ( AddBobs() ) { | |
++added; | |
} | |
if ( AddFoos() ) { | |
++added; | |
} | |
if ( AddBars() ) { | |
++added; | |
} | |
Console.WriteLine( $"{added} songs added." ); | |
return added; | |
//local functions inside a local function! | |
Boolean AddBobs() { | |
//bob! | |
try { | |
album.Add( new Music( "bob", TimeSpan.FromSeconds( rnd!.Next( 60, 90 ) ), new[] { | |
new Track( 1, "how to sing with bob" ), new Track( 2, "how to learn with bob" ), new Track( 3, "how to code with bob" ) | |
}, "best of c# album with bob" ) ); | |
return true; | |
} | |
catch ( Exception ) { | |
//could add in other checks here | |
return false; | |
} | |
} | |
Boolean AddFoos() { | |
//foo! | |
try { | |
album.Add( new Music( "foo", TimeSpan.FromSeconds( rnd!.Next( 60, 90 ) ), new[] { | |
new Track( 1, "how to sing with foo" ), new Track( 2, "how to learn with foo" ), new Track( 3, "how to code with foo" ) | |
}, "best of c# album with foo" ) ); | |
album.Add( new Music( "the best of foo", TimeSpan.FromSeconds( rnd!.Next( 60, 90 ) ), new[] { | |
new Track( 1, "how to sing with foo 2" ), new Track( 2, "how to learn with foo 2" ), new Track( 3, "how to code with foo 2" ) | |
}, "best of c# album with best of foo" ) ); | |
return true; | |
} | |
catch ( Exception ) { | |
return false; | |
} | |
} | |
Boolean AddBars() { | |
try { | |
//bar | |
album.Add( new Music( "bar", TimeSpan.FromSeconds( rnd!.Next( 60, 90 ) ), new[] { | |
new Track( 1, "how to sing with bar" ), new Track( 2, "how to learn with bar" ), new Track( 3, "how to code with bar" ) | |
}, "best of c# album with bar" ) ); | |
return true; | |
} | |
catch ( Exception ) { | |
return false; | |
} | |
} | |
} | |
} | |
private static Int32 DontWantMusic( [NotNull] Album album, [NotNull] String artist ) { | |
if ( album == null ) { | |
throw new ArgumentNullException( nameof( album ) ); | |
} | |
var removedCount = 0; | |
if ( album.Count == 0 ) { | |
return removedCount; //shortcut out of loop | |
} | |
if ( String.IsNullOrWhiteSpace( artist ) ) { | |
return removedCount; | |
} | |
CheckAgain: | |
var found = album.Where( music => music != null ) | |
.FirstOrDefault( music => music.Artist.ToWords() | |
.Contains( "foo" ) || music.SongName.ToWords() | |
.Contains( "with foo" ) ); | |
var removed = ( found != null ) && album.Remove( found ); | |
if ( removed ) { | |
++removedCount; | |
album.TrimExcess(); //remove any excess memory claimed by the list, now that we've removed an item | |
Console.WriteLine( $"The music by {found!.Artist} was removed." ); | |
//btw, people love to freak out when they see a simple goto. | |
//what they don't realize is that most code gets compiled using jumps ALL the time. seriously, look at the IL code. | |
goto CheckAgain; | |
} | |
return removedCount; | |
} | |
} | |
public static class StringExtensions { | |
[NotNull] | |
public static Char[] SplitBySpace { get; } = { | |
Singlespace[ 0 ] | |
}; | |
/// <summary>Get in the habit of using Lazy, just in case your object is never instantiated</summary> | |
[NotNull] | |
[ItemNotNull] | |
public static Lazy<Regex> ByWordBreak { get; } = new Lazy<Regex>( () => new Regex( @"(?=\S*(?<=\w))\b", RegexOptions.Compiled | RegexOptions.Singleline ) ); | |
public const String Singlespace = " "; | |
/// <summary>Join a list of <paramref name="items" /> back into a string, separated via <paramref name="separator" />.</summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="items"></param> | |
/// <param name="separator"></param> | |
/// <param name="atTheEnd"></param> | |
/// <returns></returns> | |
[DebuggerStepThrough] | |
[NotNull] | |
[Pure] | |
public static String ToStrings<T>( [NotNull] this IEnumerable<T> items, [CanBeNull] String separator = ", ", [CanBeNull] String? atTheEnd = null ) { | |
if ( items is null ) { | |
throw new ArgumentNullException( nameof( items ) ); | |
} | |
if ( String.IsNullOrEmpty( atTheEnd ) ) { | |
return String.Join( separator, items ) | |
.TrimEnd(); | |
} | |
return $"{String.Join( separator, items )}{separator}{atTheEnd}".TrimEnd(); | |
} | |
/// <summary>Break apart a string into words, via <paramref name="separator" />.</summary> | |
/// <param name="sentence"></param> | |
/// <param name="separator"></param> | |
/// <returns></returns> | |
[NotNull] | |
[ItemNotNull] | |
[Pure] | |
public static IEnumerable<String> ToWords( [CanBeNull] this String sentence, [CanBeNull] String separator = Singlespace ) => | |
ByWordBreak.Value.Split( $"{separator}{sentence}{separator}" ) | |
.ToStrings( separator ) | |
.Split( new[] { | |
separator | |
}, StringSplitOptions.RemoveEmptyEntries ); | |
} | |
public class Music { | |
[NotNull] | |
public String Artist { get; } | |
public TimeSpan Length { get; } | |
[NotNull] | |
public List<Track> Tracklist { get; } | |
[NotNull] | |
public String SongName { get; } | |
[DebuggerStepThrough] | |
public Music( String artist, TimeSpan length, IEnumerable<Track> tracklist, String songName ) { | |
if ( String.IsNullOrWhiteSpace( artist ) ) { | |
throw new ArgumentException( "Value cannot be null or whitespace.", nameof( artist ) ); | |
} | |
if ( length <= TimeSpan.Zero ) { | |
throw new ArgumentException( $"{nameof( Music )} cannot be zero or less.", nameof( length ) ); | |
} | |
if ( tracklist == null ) { | |
throw new ArgumentNullException( nameof( tracklist ) ); | |
} | |
if ( String.IsNullOrWhiteSpace( songName ) ) { | |
throw new ArgumentException( "Value cannot be null or whitespace.", nameof( songName ) ); | |
} | |
this.Artist = artist; | |
this.Length = length; | |
this.Tracklist = tracklist.ToList(); | |
this.SongName = songName; | |
} | |
} | |
public class Track { | |
public Int32 Number { get; } | |
[NotNull] | |
public String Title { get; } | |
[DebuggerStepThrough] | |
public Track( Int32 number, [NotNull] String title ) { | |
if ( number <= 0 ) { | |
throw new ArgumentOutOfRangeException( nameof( number ), $"{nameof( Track )} {nameof( this.Number )} cannot be zero or less." ); | |
} | |
if ( String.IsNullOrWhiteSpace( title ) ) { | |
throw new ArgumentException( "Value cannot be null or whitespace.", nameof( title ) ); | |
} | |
this.Number = number; | |
this.Title = title; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment