Skip to content

Instantly share code, notes, and snippets.

@Protiguous
Last active August 14, 2020 08:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Protiguous/bbbce685f592fb7d80cec04ca7bdb28a to your computer and use it in GitHub Desktop.
Save Protiguous/bbbce685f592fb7d80cec04ca7bdb28a to your computer and use it in GitHub Desktop.
Example to show adding items to a list and removing certain items.
//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