shrink byte array

  • C#
  • .NET (FX) 1.0–2.0

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von lukekogv.

    shrink byte array

    Hi,
    Also, nehmen wir an ich hab folgendes byte array gegeben:

    C#-Quellcode

    1. byte[] b = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };


    Auch existiert ein zweites byte[] das genau halb so groß ist wie b.

    C#-Quellcode

    1. byte[] c = new byte[b.Length / 2];


    Nun möchte ich per schlaufen durchlauf immer das aktuelle byte in b und das nächste zusammen addieren und zum Array c inzufügen.
    Dann muss quasi in b ein byte array übersprungen werden und die nächsten zwei addiert und zum array c geadded werden.

    d.h. am ende sollte c so aussehen:

    C#-Quellcode

    1. c[0] = 1+2;
    2. c[1] = 3+4;
    3. c[2] = 5+6
    4. c[3] = 7+8;
    5. c[4] = 9+0;


    Ich kapiere aber nicht ganz wie ich den nächsten index in C ansteuern soll und gleichzeitig ein Element in b überspringen kann.

    hat jemand eine idee wie ich das anstellen kann?
    C# Developer
    Learning C++
    Ich weiß nicht wie "schön" der Code ist und ob er überhaupt stimmt (wurde per Übersetzer von vb.net -> C# übersetzt) aber bei mir funktioniert es soweit.

    C#-Quellcode

    1. int k = 0;
    2. for (i = 0; i <= bytes1.Length - 1; i += 2) {
    3. bytes2(k) = bytes1(i) + bytes1(i + 1);
    4. k += 1;
    5. }


    mfG Frank
    Hab mittlerweile auch selbst was gebastelt bekommen :

    C#-Quellcode

    1. ​public static byte[] ShrinkArray(byte[] b)
    2. {
    3. List<byte> c = new List<byte>();
    4. for (int i = 0; i < b.Length; i++)
    5. {
    6. c.Add((byte)(b[i] + b[++i]));
    7. }
    8. return c.ToArray();
    9. }


    Danke!
    C# Developer
    Learning C++

    Rikudo schrieb:

    C#-Quellcode

    1. for (int i = 0; i < b.Length; i++)
    2. {
    3. c.Add((byte)(b[i] + b[++i]));
    4. }
    ^Dieser Code ist bei Umbau fehleranfällig und erst auf den zweiten Blick zu durchschauen.
    Wenn Du bei der For-Initialisierung i += 2 und in der Summierung [i + 1] schreibst, weiß jeder sofort, was gemeint ist.

    C#-Quellcode

    1. public static byte[] ShrinkArray(byte[] b)
    2. {
    3. List<byte> c = new List<byte>();
    4. for (int i = 0; i < b.Length; i += 2)
    5. {
    6. c.Add((byte)(b[i] + b[i + 1]));
    7. }
    8. return c.ToArray();
    9. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ein Tipp, wenn es nicht unbedingt ein Array sein muss:

    C#-Quellcode

    1. public static IEnumerable<byte> AddPairs(IEnumerable<byte> Source)
    2. {
    3. using (var Enumerator = Source.GetEnumerator())
    4. {
    5. while (true)
    6. {
    7. if (!Enumerator.MoveNext()) yield break;
    8. byte a = Enumerator.Current;
    9. if (!Enumerator.MoveNext()) yield break;
    10. byte b = Enumerator.Current;
    11. yield return (byte)(a + b);
    12. }
    13. }
    14. }

    Addiert alles paarweise.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @Niko Ortner Vom Gefühl her dürfte das aber etwas unperformanters sein. :/
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi
    ich hätte ebenfalls den Ansatz von xd-franky-5 gewählt. Er ist wohl das Effizienteste, was in .Net sinnvoll möglich ist, sowohl was Speicher betrifft, als auch was Rechenzeit betrifft.
    @NikoOrtner dein Code ist halt nicht wirklich slim, das ist irgendwie fast so, als würde man mit Kanonen auf Spatzen schießen.

    Was bei solchen Problemstellungen generell hilft, ist die Überlegung auf dem Papier. Das hier ist ein recht trivialer Fall, aber als erstes empfiehlt es sich, die Regelmäßigkeiten festzustellen. Wenn man die Regelmäßigkeit verstanden hat, gilt es nur noch, sie in mathematischen oder generell logischen Zusammenhang zu bringen.
    Außerdem lässt sich eins über Linq sagen: Es macht seinen Job, aber es ist nicht das Maß aller Dinge. Sehr häufig liegen Daten nicht einfach zufällig verteilt vor, wie es in IEnumerable der Fall ist (es gibt keine Count-Eigenschaft, das nächste Item ist beliebig konfiguriert) und durch Vererbung und is-Abfragen lässt sich sowas auch nur bedingt (und unsauber) lösen. Es gibt einfach zu viele Fälle und in manchen Fällen hat man einen guten Algorithmus (gut nicht nur in Laufzeit, Speichereffizienz, etc. gemessen, sondern auch auf Einfachheit) für ein Problem. Wenn er so einfach ist, wie einer in diesem Fall, würde ich lieber den konkreten Algorithmus implementieren, als auf Linq zu setzen.
    Übrigens: Laufzeit des Codes ist sowohl bei Array, als auch bei der amortisierten Analyse des ToArrays wohl O(n), n ist Abzahl der Items. Besser geht nicht, außer durch Parallelität. Bei näherer Betrachtung wäre aber der Koeffizient für Listen deutlich höher, da mehrere Umkopierungen vorliegen, wenn keine initiale Kapazität gewählt wird, wie es hier der Fall ist. Das zugrundeliegende Array muss bei jeder Größenänderung in das neue Array kopiert werden, da alloziierter Speicher i.A. fixed size ist, die Allokation ist teuer, das Kopieren relativ günstig, aber nicht so günstig, wie einfache Register-Operationen. D.h. pro Quellelement einmal aus dem Speicher lesen, pro Zielelement einmal schreiben ist die beste Lösung. Der Speicher ist oftmals der Flaschenhals für Prozesse.
    Sprünge und Funktionsaufrufe sind außerdem nach wie vor afaik recht teuer, d.h. ich würde darauf verzichten, sofern möglich, rein aus Optimierungssicht. Viele Algorithmen lassen sich geschickt so optimieren und wenn man sich schon mal die Mühe macht... Einmal umsetzen, wiederverwenden.

    Viele Grüße
    ~blaze~
    wobei das mit dem Enumerator für stream Daten und vorallem Daten die sinnvolle Speichergrößen überschreiten wesentlich besser, da verzichtet man lieber auf etwas performance.
    Man könnte natürlich auch mit Caching arbeiten und dann das beste aus beiden welten nehmen, ist aber dann nochmal komplizierter als beide^^
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Ich find Nikos Ansatz nicht schlecht.
    Braucht keinen Zwischenspeicher, und ist auch sehr performant - ist ja nix als eine aufgedröselte Foreach-Schleife.
    Aber ich würd bischen verbessern, v.a., dass bei ungeraden Element-Zahlen nicht das letzte Element verschluckt wird, oder gar einen Fehler produziert, wenn danach nix mehr kommt zum adden:

    C#-Quellcode

    1. public static IEnumerable<byte> AddPairs(IEnumerable<byte> Source) {
    2. using (var Enumerator = Source.GetEnumerator()) {
    3. while (Enumerator.MoveNext()) {
    4. byte a = Enumerator.Current;
    5. if (Enumerator.MoveNext()) yield return (byte)(a + Enumerator.Current);
    6. else { yield return a; yield break; }
    7. }
    8. }
    9. }
    Sprünge sind verhältnismäßig teuer, und yield ist nen Sprung, genauso wie der Rücksprung, wenn wir das nächste Element holen wollen.
    Da ist einmaliges allozieren, bzw. allozieren in O(n log n) bei ner List idR performanter
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    So, weil ich nichts Besseres zu tun hatte, noch eine weitere Lösung. Wohlgemerkt, weder schön, noch besonders performant, aber LINQ <3

    C#-Quellcode

    1. var output = input
    2. .Select((val, idx) => new { idx, val })
    3. .GroupBy(n => n.idx / 2, n => n.val, (key, grp) =>
    4. grp.Aggregate((a, b) => (byte)(a + b)))
    5. .ToArray();


    Halt einfach weil LINQ es kann :P