Trochę bardziej zaawansowane Linq

Trochę bardziej zaawansowane Linq
Qbelek
  • Rejestracja:prawie 6 lat
  • Ostatnio:3 minuty
  • Postów:102
0

W ramach ćwiczeń Linq próbuję sobie rozwiązywać prostsze zadanka z hackerranka jednolinijkowcami. Ale nie jestem w stanie znaleźć jakichś bardziej zaawansowanych przykładów w internecie. Wszędzie są tylko opisy jak działa dana funkcja. Jeśli ktoś zna jakieś źródło takich przykładów to chętnie przygarnę.

A teraz mój problem.

Mam napisać funkcję, która na wejście przyjmuje dwie listy intów tej samej długości.
Funkcja ma zwrócić również listę intów, w której pierwszy wyraz ma mówić ile razy wyraz pierwszej listy był większy niż odpowiadający wyraz drugiej listy.
Drugi wyraz odwrotnie.
Jeśli odpowiadające sobie wyrazy są równe to nie zwiększamy żadnego z wyrazów listy wynikowej.

Przykład:

a = {1, 2, 3}
b = {2, 2, 3}

1 < 2
2 = 2
3 = 3

wynik = {0, 1}

Mam takie cuś:

Kopiuj
public static List<int> Resolve(List<int> a, List<int> b)
        {
            var ar = a.Select(x => x).Count(x => x > b[a.IndexOf(x)]);
            var br = b.Select(x => x).Count(x => x > a[b.IndexOf(x)]);
            return new List<int> {ar, br};
        }

I nie mogę dojść do tego jak można użyć Linq, żeby jedno zapytanie od razu zwracało wynikową listę.

Tasmanian Devil
Hej! Twój post prawdopodobnie zawiera niesformatowany kod. Użyj znaczników ``` aby oznaczyć, co jest kodem, będzie łatwiej czytać. (jestem botem, ta akcja została wykonana automatycznie, prawdopodobieństwo 0.99958706)
SA
  • Rejestracja:około 12 lat
  • Ostatnio:około 2 godziny
  • Postów:1431
1

Poczytaj o Zip i Aggregate. I na MSDN są przykłady.

edytowany 1x, ostatnio: Saalin
UR
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 3 lata
  • Postów:360
1

Tak jak kolega wyżej napisał plus ewentualnie możesz zjoinować po indeksach.

Qbelek
  • Rejestracja:prawie 6 lat
  • Ostatnio:3 minuty
  • Postów:102
0

No o .Zip() czytałem, do tego doszedłem jak scalić te elementy list. Problem mam z inkrementacją jednego z dwóch elementów w zależności od spełnienia warunku.
I jak to zrobić bez wcześniejszej inicjalizacji wyjściowej listy z dwoma zerami?

UR
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 3 lata
  • Postów:360
1

Żebyś nie miał za prosto i mógł sobie przećwiczyć, to sobie zoptymalizuj ten overengineering :D

Kopiuj
  List<int> a = new List<int> { 1, 2, 3, 1, 5, 8, 1 };
  List<int> b = new List<int> { 2, 2, 3, 4, 0, 1, 9 };


            var xxxxxx = a.Select((item, index) => new { item, index })
                        .Join(b.Select((item, index) => new { item, index }),
                          aItem => aItem.index,
                          bItem => bItem.index,
                          (aItem, bItem) => new { greater = aItem.item > bItem.item ? "a" : aItem.item == bItem.item ? "none" : "b" })
                        .Where(x => x.greater != "none")
                        .OrderBy(x => x.greater)
                        .GroupBy(x => x.greater)
                        .Select(x => x.Count());


            var wtf = a.Select((item, index) => new { item, index }).Aggregate(new Dictionary<string, int>(),
                (result, aListItemWithIndex) =>
                {
                    string key = aListItemWithIndex.item > b[aListItemWithIndex.index] ? "a" :
                        aListItemWithIndex.item < b[aListItemWithIndex.index] ? "b" : "none";
                    int value = aListItemWithIndex.item > b[aListItemWithIndex.index] ? 1
                        : aListItemWithIndex.item == b[aListItemWithIndex.index] ? 0 : 1;

                    if (!result.TryAdd(key, value))
                    {
                        result[key] += value;
                    }
                    return result;
                }).Where(x => x.Key != "none").OrderBy(x => x.Key).Select(x => x.Value);

somekind
No nie powiem, na Oscara za horror roku szanse są duże.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 dni
  • Lokalizacja:Wrocław
1

To raczej nie jest kwestia użycia LINQ lecz wymyślenia jak z tych dwóch list zrobisz jedną, zawierającą informacje o tym, w której ze źródłowych list element był większy. Może w tym pomóc odejmowanie. ;)

obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:2 minuty
1

Tak jak wyżej - zip i aggregate

"oneliner" (rozbity na linie dla komentarzy):

Kopiuj
a.Zip(b, (x, y) => new // przyjmujesz parę elementów z kolekcji a i b jako (x, y)
	{
		x = x > y ? 1 : 0, // zwróć obiekt z dwoma własnościami mówiącymi kolejno czy x>y i czy y>x
		y = y > x ? 1 : 0
	})
	.Aggregate(
		new int[2], // typ zwróconego obiektu i zarazem wartość początkowa - pusta tablica dwuelementowa
		(result, row) => { result[0] += row.x; result[1] += row.y; return result; } // dodajemy wartości do wyniku i zwracamy ten sam obiekt
	);

albo wykorzystując odejmowanie

Kopiuj
a.Zip(b, (x, y) => x - y) // zwracasz tylko różnicę elementów - ujemny wynik oznacza że y był większy od x
	.Aggregate(
		new int[2], // typ zwróconego obiektu i zarazem wartość początkowa - pusta tablica dwuelementowa
		(result, row) =>
		{
				result[0] += row > 0 ? 1 : 0;
				result[1] += row < 0 ? 1 : 0;
				return result;  // dodajemy wartości do wyniku i zwracamy ten sam obiekt
		}
	).Dump();

z tym że odejmowanie tutaj to trochę hack i nie działa dla skrajnych wartości (np int.MinValue i int.MaxValue daje odwrotny wynik, możesz rzutować do longa dla precyzji)
miałem nie wrzucać gotowego rozwiązania ale po odpowiedzi urke poczułem jakby ktoś mi obrażał Linq
poćwicz na trudniejszym przykładzie, albo spróbuj skrócić jeszcze ten bo można to zrobić choćby kosztem pamięci z użyciem tupli


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 4x, ostatnio: obscurity
UR
  • Rejestracja:prawie 5 lat
  • Ostatnio:prawie 3 lata
  • Postów:360
1

miałem nie wrzucać gotowego rozwiązania ale po odpowiedzi urke poczułem jakby ktoś mi obrażał Linq

Przecież to specjalnie po to żeby przećwiczył, bo już w pierwszym poście walnął tragiczny błąd logiczny, w którym porównuje po pierwszym indeksie danej liczby, zamiast po poprawnych indeksach.

Jak mam być upierdliwy i skoro i tak podałeś już rozwiązanie, to tutaj zip nie jest potrzebny

Kopiuj
           
List<int> a = new List<int> { 1, 2, 3, 1, 5, 8, 1 };
           
List<int> b = new List<int> { 2, 2, 3, 4, 0, 1, 9 };

            
var x = a.Select((item, index) => new { a = item > b[index] ? 1 : 0, b = b[index] > item ? 1 : 0 }).Aggregate(new List<int>(2) { 0, 0 }, (result, curr) => { result[0] += curr.a; result[1] += curr.b; return result; });
edytowany 1x, ostatnio: urke
obscurity
zastąpiłeś tylko Zip Selectem który robi to samo, ale uniemożliwia zrobienie z tego jednolinijkowca
UR
Kwestia zapisu. Można zapisac i tak a.Select((aIt, aInd) => aIt - b[aInd]).Aggregate(new int[2], (result, curr) => { result[0] += curr > 0 ? 1 : 0; result[1] += curr < 0 ? 1 : 0; return result; }); I jest wtedy takiej samej długości jak solucja z zipem. Co nie zmienia faktu, że ani jednej, ani drugiej jednolinijkowcem bym nie nazwał, bo linie na 160 + znaków.
Qbelek
Faktycznie! Po nazwie założyłem, że ta funkcja zwraca poprawny indeks i nie doczytałem dokumentacji. Ale po namyśle nie wiem jak miałoby to niby działać skoro przyjmuje inta jako argument. Mój błąd :c
somekind
O, wreszcie ktoś odkrył odejmowanie, o którym pisałem wczoraj. :) No i mimo wszystko z Zipem to jakoś ładniej wygląda niż z Selectem, w sensie Zip ładniej pokazuje intencje - że operujemy na dwóch równolicznych kolekcjach.
obscurity
@somekind: no pisałem o odejmowaniu w poprzednim poście, wygląda niby fajnie, ale tak naprawdę to zbugowany kod, który nie działa dla edge case'ów z przekroczeniem zakresu i nie nadaje się do stosowania w produkcyjnym kodzie. @urke: a.Zip(b,(x,y)=>new[]{x>y?1:0,y>x?1:0}).Aggregate((x,y)=>new[]{x[0]+y[0],x[1]+y[1]}) 84 znaki bez białych znaków i z olaniem pamięci, przyjmujesz jako jednolinijkowiec? byłoby 10 znaków krócej gdyby nie wymóg arraya jako outputu
somekind
No fakt, podejście mocno zależy od tego jakie mamy ograniczenia na dane wejściowe (a w takich zadankach zazwyczaj jest to sprecyzowane).
Qbelek
  • Rejestracja:prawie 6 lat
  • Ostatnio:3 minuty
  • Postów:102
1
obscurity napisał(a):
Kopiuj
a.Zip(b, (x, y) => new // przyjmujesz parę elementów z kolekcji a i b jako (x, y)
	{
		x = x > y ? 1 : 0, // zwróć obiekt z dwoma własnościami mówiącymi kolejno czy x>y i czy y>x
		y = y > x ? 1 : 0
	})
	.Aggregate(
		new int[2], // typ zwróconego obiektu i zarazem wartość początkowa - pusta tablica dwuelementowa
		(result, row) => { result[0] += row.x; result[1] += row.y; return result; } // dodajemy wartości do wyniku i zwracamy ten sam obiekt
	);

Właśnie coś takiego próbowałem zrobić tylko nie wiedziałem jaka będzie składnia, zwłaszcza nie wiedziałem co dać jako 1szy argument .Aggregate().

PI
  • Rejestracja:prawie 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:2
0

Zip + Aggregate lub coś takiego

Kopiuj
 a.Zip(b).GroupBy(x => new { }).Select(x => new 
            { 
                first = x.Count(s => s.First > s.Second), 
                second = x.Count(s => s.First < s.Second)
            });
edytowany 2x, ostatnio: Pioterr
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)