Working with Strings

Concatenation

string str1 = "Hello";
string str2 = "World";
string result = string.Concat(str1, " ", str2);
// Result: "Hello World"

Format

string formatted = string.Format("Name: {0}, Age: {1}", "Alice", 30);
// Result: "Name: Alice, Age: 30"

Remove and Insert

string text = "Hello, World!";
string removed = text.Remove(5, 7);
// Result: "Hello!"
string inserted = text.Insert(5, "Beautiful ");

SubstringBefore and SubstringAfter (Custom Extensions)

string text = "This is a sample text.";
string before = text.SubstringBefore("sample");
string after = text.SubstringAfter("sample");
// before: "This is a ", after: " text."

CopyTo

// public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);
string text = "Hello, World!";
char[] charArray = new char[5];
text.CopyTo(0, charArray, 0, 5);
// Result: charArray contains ['H', 'e', 'l', 'l', 'o']

LINQ on Strings

Select

Use Select to transform each character in a string and project into a new string or collection.

string text = "Hello, LINQ!";
string transformed = new string(text.Select(c => char.ToUpper(c)).ToArray());
// Result: "HELLO, LINQ!"

Where

Use Where to filter characters based on a condition.

string text = "Hello, LINQ!";
string filtered = new string(text.Where(c => char.IsLetter(c)).ToArray());
// Result: "HelloLINQ"

Concatenate

Use string.Concat or string.Join with Select to concatenate characters or strings.

string[] words = { "Hello", "LINQ" };
string concatenated = string.Concat(words.Select(word => word + " "));
// Result: "Hello LINQ "

Aggregate

Use Aggregate to perform cumulative operations on characters.

string text = "Hello, LINQ!";
string combined = text.Aggregate((result, nextChar) => result + nextChar.ToString().ToUpper());
// Result: "HELLO, LINQ!"

Reverse

string text = "Hello, LINQ!";
string reversed = new string(text.Reverse().ToArray());
// Result: "!QNIL ,olleH"

OrderBy and OrderByDescending

string text = "cba";
string sorted = new string(text.OrderBy(c => c).ToArray());
// Alphabetical: "abc"
string reverseSorted = new string(text.OrderByDescending(c => c).ToArray());
// Reverse alphabetical: "cba"

GroupBy

string text = "Hello, LINQ!";
var grouped = text.GroupBy(c => c);
foreach (var group in grouped)
{
    Console.WriteLine($"Character: {group.Key}, Count: {group.Count()}");
}

Distinct

string text = "aaabbbccc";
string uniqueCharacters = new string(text.Distinct().ToArray());
// Result: "abc"

Skip and Take

string text = "Hello, LINQ!";
string substring = new string(text.Skip(7).Take(5).ToArray());
// Result: "LINQ!"

Zip

string str1 = "Hello";
string str2 = "World";
 
string combined = string.Join(", ", str1.Zip(str2, (c1, c2) => $"{c1}-{c2}")); // Result: "H-W, e-o, l-r, l-l, o-d"

Any and All

string text = "Hello, LINQ!";
bool hasUppercase = text.Any(char.IsUpper);  // Check if there are uppercase letters
bool allLetters = text.All(char.IsLetter);   // Check if all characters are letters

String Interpolation with Select

string[] data = { "Alice", "Bob", "Charlie" };
var formattedData = data.Select(name => $"{name} is awesome!");

TakeWhile and SkipWhile

string text = "12345Hello6789";
string result = new string(text.SkipWhile(char.IsDigit).ToArray());
// Result: "Hello6789" (digits are skipped)

String Concatenation with Aggregate

string[] words = { "Hello", "LINQ", "is", "powerful" };
string concatenated = words.Aggregate((current, next) => current + " " + next);
// Result: "Hello LINQ is powerful"

String Split and Rejoin

string sentence = "This is a sample sentence.";
var words = sentence.Split(' ');
string reversed = string.Join(" ", words.Select(word => new string(word.Reverse().ToArray())));
// Result: "sihT si a elpmas .ecnetnes"

String Comparison

string text = "hello world";
bool containsHello = text.Split(' ').Any(word => string.Equals(word, "hello", StringComparison.OrdinalIgnoreCase));

Merging Strings from a List

List<string> items = new List<string> { "apple", "banana", "cherry" };
string merged = string.Join(", ", items);
// Result: "apple, banana, cherry"

String Searching with IndexOf and LINQ

string text = "Hello, LINQ!";
var indices = Enumerable.Range(0, text.Length).Where(i => text[i] == 'L');
// Result: [7]

Combining Select and Join

string text = "Hello, LINQ!";
string transformedAndJoined = string.Join("", text.Select(c => char.IsLetterOrDigit(c) ? char.ToUpper(c) : c));
// Result: "HELLO, LINQ!"

Frequent Character Count

string text = "abracadabra";
var mostFrequentChar = text.GroupBy(c => c).OrderByDescending(group => group.Count()).First().Key;
// Result: 'a' (appears 5 times)

Word Count in a Sentence

string sentence = "This is a sample sentence.";
int wordCount = sentence.Split(' ').Count();
// Result: 5

Replacing Multiple Substrings

string text = "I like cats and dogs.";
var replacements = new Dictionary<string, string> { { "cats", "apples" }, { "dogs", "bananas" } };
string replaced = text;
foreach (var replacement in replacements)
{
    replaced = replaced.Replace(replacement.Key, replacement.Value);
}
// Result: "I like apples and bananas."

Distinct Letters in a String

string text = "hello world";
var distinctLetters = text.Where(char.IsLetter).Distinct();
// Result: ['h', 'e', 'l', 'o', 'w', 'r', 'd']

Joining with Line Breaks

List<string> lines = new List<string> { "Line 1", "Line 2", "Line 3" };
string joinedWithLineBreaks = string.Join(Environment.NewLine, lines);

String Padding with Select

string text = "Line 1\nLine 2\nLine 3";
int padding = 2;
string paddedText = string.Join("\n", text.Split('\n').Select(line => line.PadLeft(padding + line.Length)));

Common String Problems

First Non-Repeating Character

char firstNonRepeatingChar = input.FirstOrDefault(c => input.Count(x => x == c) == 1) ?? ' ';

Reverse Words in a String

string reversedWords = string.Join(" ", input.Split(' ').Reverse());

Remove All Vowels

string withoutVowels = new string(input.Where(c => !"aeiouAEIOU".Contains(c)).ToArray());

Anagram Check

bool isAnagram = string.Concat(s.OrderBy(c => c)) == string.Concat(t.OrderBy(c => c));

Sum of Digits in a String

// c - '0' converts a digit character to its numeric value (e.g. '5' - '0' = 5)
int sumOfDigits = input.Where(char.IsDigit).Sum(c => c - '0');

Palindrome Check

bool isPalindrome = input.SequenceEqual(input.Reverse());

Word Count (Handles Multiple Spaces)

int wordCount = input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;

Index of First Non-Repeating Character

int firstNonRepeatingIndex = input.Select((c, index) => new { Char = c, Index = index })
    .GroupBy(item => item.Char)
    .Where(group => group.Count() == 1)
    .Select(group => group.First().Index)
    .DefaultIfEmpty(-1)
    .First();

Most Frequent Character

char mostFrequentChar = input.GroupBy(c => c)
    .OrderByDescending(group => group.Count())
    .First()
    .Key;

Characters Sorted by Frequency (Then Alphabetically)

var sortedChars = input
    .GroupBy(c => c)
    .OrderByDescending(group => group.Count())
    .ThenBy(group => group.Key)
    .Select(group => group.Key)
    .ToList();

Reverse Order of Words

return string.Join(" ", s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Reverse());

First Non-Repeating Character (Return Space if None)

return s.FirstOrDefault(c => s.Count(x => x == c) == 1) ?? ' ';

Characters Appearing More Than Once (Sorted)

return new string(s.Where(c => s.Count(x => x == c) > 1).Distinct().OrderBy(c => c).ToArray());

Characters Appearing Exactly Twice

var charactersAppearingTwice = input.GroupBy(c => c)
    .Where(group => group.Count() == 2)
    .Select(group => group.Key)
    .ToList();

Valid Subsequence Check

bool IsValidSubstring(string s, string t)
{
    int sIndex = 0;
    return t.All(tChar =>
    {
        while (sIndex < s.Length && s[sIndex] != tChar)
            sIndex++;
        return sIndex < s.Length && s[sIndex++] == tChar;
    });
}

Group Words by Anagram

List<List<string>> GroupAnagrams(List<string> words)
{
    return words.GroupBy(w => new string(w.OrderBy(c => c).ToArray()))
        .Select(group => group.ToList())
        .ToList();
}

Longest Common Prefix

// Iterates through strings and progressively updates the prefix by comparing characters.
// Zip stops at the shorter string, so mismatches beyond that are handled automatically.
string LongestCommonPrefix(List<string> strings)
{
    if (strings.Count == 0) return "";
 
    string prefix = strings.First();
    foreach (string s in strings.Skip(1))
    {
        prefix = new string(prefix.Zip(s, (a, b) => a == b ? a : ' ').ToArray());
        if (string.IsNullOrEmpty(prefix)) break;
    }
    return prefix;
}

Working with Arrays

Filtering — Where

int[] numbers = { 1, 2, 3, 4, 5, 6 };
var evenNumbers = numbers.Where(n => n % 2 == 0);

Projection — Select

string[] words = { "apple", "banana", "cherry" };
var lengths = words.Select(w => w.Length);

Sorting — OrderBy

string[] fruits = { "cherry", "banana", "apple" };
var sortedFruits = fruits.OrderBy(f => f);

Aggregation — Sum, Max, Min, Average

int[] scores = { 85, 92, 78, 90, 88 };
int totalScore = scores.Sum();
int highestScore = scores.Max();
int lowestScore = scores.Min();
double avgScore = scores.Average();

Counting — Count

int[] numbers = { 1, 2, 3, 4, 5, 6 };
int evenCount = numbers.Count(n => n % 2 == 0);

Existence — Any, All

int[] numbers = { 1, 2, 3, 4, 5, 6 };
bool hasEven = numbers.Any(n => n % 2 == 0);
bool allPositive = numbers.All(n => n > 0);

Distinct

int[] numbers = { 1, 2, 2, 3, 4, 4, 5 };
var distinctNumbers = numbers.Distinct();

Joining Two Arrays — Join

string[] names = { "Alice", "Bob", "Charlie" };
int[] ages = { 30, 25, 35 };
var nameAgePairs = names.Join(ages, n => n, a => a.ToString(), (n, a) => $"{n} is {a} years old");

Element Access — First, Last, ElementAt

int[] numbers = { 1, 2, 3, 4, 5 };
int firstNumber = numbers.First();
int lastNumber = numbers.Last();
int thirdNumber = numbers.ElementAt(2);

Skip and Take

int[] numbers = { 1, 2, 3, 4, 5, 6 };
var skippedNumbers = numbers.Skip(2);  // Skips first 2 elements
var takenNumbers = numbers.Take(3);    // Takes first 3 elements

Concatenation — Concat

int[] firstArray = { 1, 2, 3 };
int[] secondArray = { 4, 5, 6 };
var concatenated = firstArray.Concat(secondArray);

Distinct with Custom Comparer

string[] words = { "apple", "banana", "cherry" };
var distinctWords = words.Distinct(StringComparer.OrdinalIgnoreCase);

Grouping — GroupBy

string[] fruits = { "apple", "banana", "cherry", "blueberry" };
var groups = fruits.GroupBy(f => f.Length);

Join with Custom Criteria

int[] numbers = { 1, 2, 3, 4, 5 };
string[] words = { "one", "two", "three", "four", "five" };
var result = numbers.Join(words, n => n.ToString(), w => w.Length.ToString(), (n, w) => $"{n}: {w}");

Union

int[] firstArray = { 1, 2, 3 };
int[] secondArray = { 3, 4, 5 };
var uniqueNumbers = firstArray.Union(secondArray);

Aggregate with Initial Value

int[] numbers = { 1, 2, 3, 4, 5 };
int product = numbers.Aggregate(1, (acc, num) => acc * num);

Zip

int[] numbers1 = { 1, 2, 3 };
int[] numbers2 = { 4, 5, 6 };
var zippedPairs = numbers1.Zip(numbers2, (a, b) => $"{a}-{b}");

Distinct by Property

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
 
var people = new List<Person>
{
    new Person { Name = "Alice", Age = 30 },
    new Person { Name = "Bob", Age = 25 },
    new Person { Name = "Alice", Age = 30 }
};
 
var distinctPeople = people.Distinct(new PersonComparer());

Partitioning — SkipWhile, TakeWhile

int[] numbers = { 1, 2, 3, 4, 5, 6 };
var afterTwo = numbers.SkipWhile(n => n < 3);   // Skips until condition is false
var untilFour = numbers.TakeWhile(n => n <= 4); // Takes until condition is false

Custom Aggregation

int[] numbers = { 1, 2, 3, 4, 5 };
string result = numbers.Aggregate("Numbers: ", (acc, num) => $"{acc}{num}, ", acc => acc.TrimEnd(',', ' '));

Element Removal — Except

int[] numbers1 = { 1, 2, 3, 4, 5 };
int[] numbersToRemove = { 3, 4 };
var remainingNumbers = numbers1.Except(numbersToRemove);

2D Array — Filter Even Numbers and Reshape

int[,] matrix = {
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};
 
var flattened = matrix.Cast<int>();
var evenNumbers = flattened.Where(num => num % 2 == 0);
 
int numRows = matrix.GetLength(0);
int numCols = matrix.GetLength(1);
 
int[][] reshaped = evenNumbers
    .Select((value, index) => new { value, index })
    .GroupBy(item => item.index / numCols)
    .Select(group => group.Select(item => item.value).ToArray())
    .ToArray();

2D Array — Fibonacci-like Manipulation

int[,] matrix = {
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};
 
var flattened = matrix.Cast<int>().ToArray();
 
var result = flattened.Select((value, index) => new
{
    Value = value + (index > 0 ? flattened[index - 1] : 0),
    Index = index
}).ToArray();
 
int numRows = matrix.GetLength(0);
int numCols = matrix.GetLength(1);
int[,] reshaped = new int[numRows, numCols];
 
foreach (var item in result)
{
    int row = item.Index / numCols;
    int col = item.Index % numCols;
    reshaped[row, col] = item.Value;
}

Working with Lists

Common Operations

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 
IEnumerable<int> evens                = numbers.Where(n => n % 2 == 0);
IEnumerable<int> odds                 = numbers.Where(n => n % 2 != 0);
IEnumerable<int> greaterThanFive      = numbers.Where(n => n > 5);
IEnumerable<int> lessThanFive         = numbers.Where(n => n < 5);
 
int sum          = numbers.Sum();
int max          = numbers.Max();
int min          = numbers.Min();
double average   = numbers.Average();
 
IEnumerable<int> distinctNumbers = numbers.Distinct();
int firstOrDefault               = numbers.FirstOrDefault();
int lastOrDefault                = numbers.LastOrDefault();
 
IEnumerable<int> takeFirstThree  = numbers.Take(3);
IEnumerable<int> skipFirstThree  = numbers.Skip(3);
 
IEnumerable<int> ascendingOrder  = numbers.OrderBy(n => n);
IEnumerable<int> descendingOrder = numbers.OrderByDescending(n => n);
 
bool anyGreaterThanTen  = numbers.Any(n => n > 10);
bool allGreaterThanZero = numbers.All(n => n > 0);
 
int countGreaterThanFive = numbers.Count(n => n > 5);
bool containsFive        = numbers.Contains(5);
 
IEnumerable<int> squaredNumbers = numbers.Select(n => n * n);
int evenSquaredSum = numbers.Where(n => n % 2 == 0).Select(n => n * n).Sum();

Conversions

IEnumerable<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
 
string numberString         = string.Join(", ", numbers);
List<int> numberList        = numbers.ToList();
int[] numberArray           = numbers.ToArray();
HashSet<int> numberHashSet  = new HashSet<int>(numbers);
Dictionary<int, int> numberDictionary = numbers.ToDictionary(n => n, n => n);
string concatenatedString   = numbers.Aggregate("", (current, next) => current + next);

Example: People by City

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
}
 
List<Person> people = new List<Person>
{
    new Person { Name = "Alice",   Age = 30, City = "New York" },
    new Person { Name = "Bob",     Age = 25, City = "Los Angeles" },
    new Person { Name = "Charlie", Age = 35, City = "Chicago" },
    new Person { Name = "David",   Age = 28, City = "New York" },
    new Person { Name = "Eva",     Age = 32, City = "Los Angeles" }
};
 
// Average age in New York
double averageAgeInNY = people.Where(p => p.City == "New York").Average(p => p.Age);
 
// Count per city
var cityGrouping = people.GroupBy(p => p.City)
                         .Select(g => new { City = g.Key, Count = g.Count() });
 
// Youngest in LA
Person youngestInLA = people.Where(p => p.City == "Los Angeles")
                            .OrderBy(p => p.Age)
                            .First();
 
// Anyone above 40?
bool isAnyoneAbove40 = people.Any(p => p.Age > 40);
 
// Order by age, then name
var orderedPeople = people.OrderBy(p => p.Age).ThenBy(p => p.Name);

Example: Invoice and Product Revenue by Category

class Invoice
{
    public int InvoiceId { get; set; }
    public int ProductId { get; set; }
    public decimal Amount { get; set; }
    public DateTime InvoiceDate { get; set; }
}
 
class Product
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public string Category { get; set; }
}
 
// Filter invoices by year, join with products, group by category, sum revenue
int targetYear = 2023;
 
var productRevenueByCategory = invoices
    .Where(invoice => invoice.InvoiceDate.Year == targetYear)
    .Join(products,
          invoice => invoice.ProductId,
          product => product.ProductId,
          (invoice, product) => new { product.Category, invoice.Amount })
    .GroupBy(item => item.Category)
    .Select(group => new
    {
        Category = group.Key,
        TotalRevenue = group.Sum(item => item.Amount)
    });

Working with Dictionaries

Filtering — Where

var dictionary = new Dictionary<string, int>
{
    { "Alice", 30 }, { "Bob", 25 }, { "Charlie", 35 }, { "David", 28 }, { "Eva", 32 }
};
 
var adults = dictionary.Where(entry => entry.Value >= 30);

Projection — Select

var namesOnly = dictionary.Select(entry => entry.Key);

Sorting — OrderBy

var sortedByName = dictionary.OrderBy(entry => entry.Key);
var sortedByAge  = dictionary.OrderBy(entry => entry.Value);

Aggregation

int totalAge    = dictionary.Sum(entry => entry.Value);
int maxAge      = dictionary.Max(entry => entry.Value);
int minAge      = dictionary.Min(entry => entry.Value);
double avgAge   = dictionary.Average(entry => entry.Value);

Counting

int adultsCount = dictionary.Count(entry => entry.Value >= 30);

Existence — ContainsKey, ContainsValue

bool hasKey   = dictionary.ContainsKey("Alice");
bool hasValue = dictionary.ContainsValue(25);

Common Operations

var entryCount       = dictionary.Count;
var anyAdultsExist   = dictionary.Any(entry => entry.Value >= 30);
var allAgesBelow40   = dictionary.All(entry => entry.Value < 40);
var charlieAge       = dictionary.FirstOrDefault(entry => entry.Key == "Charlie").Value;
var nameList         = dictionary.Select(entry => entry.Key).Aggregate((a, b) => a + ", " + b);
var evenAges         = dictionary.Where(entry => entry.Value % 2 == 0).ToDictionary(e => e.Key, e => e.Value);
var namesInUpperCase = dictionary.Select(entry => entry.Key.ToUpper());
var sortedNames      = dictionary.OrderBy(entry => entry.Key).ToDictionary(e => e.Key, e => e.Value);

Example: Student Scores — Average and Above-Average per Subject

var studentScores = new Dictionary<string, List<int>>
{
    { "Math",    new List<int> { 85, 90, 78, 92, 88 } },
    { "Science", new List<int> { 75, 82, 88, 96, 70 } },
    { "History", new List<int> { 90, 85, 76, 88, 92 } }
};
 
// Average per subject
var subjectAverages = studentScores
    .Select(entry => new { Subject = entry.Key, AverageScore = entry.Value.Average() })
    .ToDictionary(item => item.Subject, item => item.AverageScore);
 
// Scores above subject average
var studentsAboveAverage = studentScores.SelectMany(entry =>
    entry.Value
        .Where(score => score > subjectAverages[entry.Key])
        .Select(score => new { Subject = entry.Key, StudentScore = score })
);

Example: Library — Authors, Recent Books, Average Year

// Task 1: Authors with more than one book
var multiBookAuthors = library.Where(entry => entry.Value.Count > 1).Select(entry => entry.Key);
 
// Task 2: Most recent book per author
var mostRecentBooks = library.Select(entry => new
{
    Author = entry.Key,
    MostRecentBook = entry.Value.OrderByDescending(book => book.PublicationYear).First()
});
 
// Task 3: Average publication year across all books
var averagePublicationYear = library.SelectMany(entry => entry.Value)
                                    .Average(book => book.PublicationYear);

Example: Student Grades — Top Scorers, Best Course, Overall Average

// Task 1: Students with highest total grade
var topScoringStudents = studentRecords
    .OrderByDescending(entry => entry.Value.Sum(course => course.Grade))
    .TakeWhile((_, index) => index == 0)
    .Select(entry => entry.Key);
 
// Task 2: Course with highest average grade
var courseAverages = studentRecords.SelectMany(entry => entry.Value)
    .GroupBy(course => course.CourseName)
    .Select(group => new { CourseName = group.Key, AverageGrade = group.Average(c => c.Grade) })
    .OrderByDescending(course => course.AverageGrade)
    .TakeWhile((_, index) => index == 0)
    .Select(course => course.CourseName);
 
// Task 3: Overall average grade
var overallAverageGrade = studentRecords.SelectMany(entry => entry.Value)
                                        .Average(course => course.Grade);

Example: Social Network — Connections and Shortest Path

class UserConnections
{
    public string Username { get; set; }
    public List<string> Connections { get; set; }
}
 
// Task 1: User with most connections
var mostConnectedUser = userNetwork
    .OrderByDescending(entry => entry.Value.Connections.Count)
    .Select(entry => entry.Key)
    .First();
 
// Task 2: Friends of friends of "Alice"
var targetUser = "Alice";
var friendsOfFriends = userNetwork
    .Where(entry => entry.Key != targetUser)
    .Where(entry => !entry.Value.Connections.Contains(targetUser))
    .Where(entry => entry.Value.Connections.Intersect(userNetwork[targetUser].Connections).Any())
    .Select(entry => entry.Key);
 
// Task 3: Shortest path between "Alice" and "David" (BFS)
var startUser = "Alice";
var endUser = "David";
 
var visited = new HashSet<string>();
var queue = new Queue<List<string>>();
queue.Enqueue(new List<string> { startUser });
 
while (queue.Count > 0)
{
    var path = queue.Dequeue();
    var currentUser = path.Last();
 
    if (currentUser == endUser)
    {
        Console.WriteLine("Shortest Path: " + string.Join(" -> ", path));
        break;
    }
 
    if (visited.Contains(currentUser)) continue;
    visited.Add(currentUser);
 
    foreach (var connection in userNetwork[currentUser].Connections)
    {
        if (!visited.Contains(connection))
        {
            var newPath = new List<string>(path) { connection };
            queue.Enqueue(newPath);
        }
    }
}