1
votes

Comment partager un nombre entier donné et son reste sur n'importe quel nombre de personnes avec LINQ?

J'ai cette boucle actuelle (ce n'est pas la vraie bc ne peut pas partager la vraie, mais l'algorithme est le même):

quantity_between_people = Math.round(total_item_quantity / people.Count());

people.(select x=> { x.quantity = quantity_between_people; return x; })

Résultat si la liste de personnes contient 3 personnes et item_quantity vaut 20:

  • nom: personne1 quantité: 7
  • nom: personne2 quantité: 7
  • nom: personne3 quantité: 6

parce que 7 + 7 + 6 = 20

Résultat si la liste de personnes contient 3 personnes et item_quantity est 1:

  • nom: personne1 quantité: 1
  • nom: personne2 quantité: 0
  • nom: personne3 quantité: 0

car il n'y a qu'un seul élément au total

Résultat si la liste de contacts contient 1 personne et que item_quantity est égal à 5:

  • nom: personne1 quantité: 5

Résultat si la liste de personnes contient x personnes et item_quantity est y:

?

Eh bien, vous voyez l'idée ...

Comme vous pouvez le voir, je ne demande pas comment le faire, je l'ai déjà fait.

Je sais comment le partager également, c'est juste une division: [total_item_quantity / number of people in the people list] .

Ce serait quelque chose comme ceci:

class People {
    public string name { get; set; }
    public int quantity { get; set; }

    People() {
      this.name = '';
      this.quantity = 0;
    }

    People(string name) {
      this.name = name;
      this.quantity = 0;
    }
}

Class ItemShare {
    items_remaining = True;
    // Shared items counter
    q = 0; 

    public void share(int total_item_quantity, IEnumerable<People> people) {

        // If there's still items to be shared we begin to share them across people
        // until there are no items left
        while items_remaining{
            foreach People p in people {
                // adds 1 to counter
                q++ 
                // If counter is less or equal to tota quantity then we can still share 
                // that item to current person
                if (q <= total_item_quantity) {             
                    p.quantity++  // Increase quantity by 1
                } else {
                    // Turn off the flag, because there are no more items to be shared
                    items_remaining= False                     
                    break; // Break loop
                }
            }
        // Print results
        foreach p in People {
            Console.WriteLine($"name:{p.name} quantity: p.quantity")
        }
    }
}

...

static void main() {
    List<People> people = getPeopleFromDB();
    // It's just an integer variable from DB
    total_item_quantity = getQuantityFromDB(); 
    var c = new ItemShare();
    c.share(total_item_quantity, people);
}

Mais si vous regardez soigneusement à la liste des résultats, vous devez prendre en compte le reste de la division. C'est mon problème. Ce que j'ai besoin de savoir, c'est, si possible. Comment le faire dans LINQ?


0 commentaires

3 Réponses :


0
votes

Je ne suis pas sûr d'avoir bien compris votre question, mais comme je peux le voir dans votre code, vous avez une boucle foreach inutile à la fin de la boucle while.

Vous pouvez placer Console.WriteLine ($ "name: {p.Name} quantity: {p.Quantity}"); à l'intérieur de l'instruction if et éviter de parcourir à nouveau la liste des personnes .

Voici à quoi devrait ressembler votre méthode:

public void share(int total_item_quantity, IEnumerable<People> people) 
{

    while (items_remaining)
                {
                    foreach (People p in people)
                    {
                        // adds 1 to counter
                        q++;

                        if (q <= total_item_quantity)
                        {
                            p.quantity++;  // Increase quantity by 1
                            Console.WriteLine($"name:{p.name} quantity: {p.quantity}");
                        }
                        else
                        {                           
                            items_remaining = false;
                            break; // Break loop
                        }
                    }
           }
}


1 commentaires

ce n'est pas le problème, le problème est de partager un nombre entre x objets, y compris le reste. Bien sûr, cela ne sert à rien ...



0
votes

J'ai écrit le code pour exactement ce que vous cherchiez. Problème très intéressant.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Distribution
{
    class Program
    {
        public class People
        {
            public string Name { get; set; }
            public int Quantity { get; set; }
        }

        public static void Main()
        {
            var totalQuantity = 5;
            var peoples = new List<string> { "John","Jack" };

            var count = peoples.Count();
            decimal quantityRaw = (decimal)totalQuantity / (decimal)count;
            int quantity = (int)Math.Ceiling(quantityRaw);

            var finalList = peoples.Select(x =>
            new People()
            {
                Name = x,
                Quantity = GetQuantity(quantity, totalQuantity, peoples.IndexOf(x))
            });

            foreach (var p in finalList)
            {
                Console.WriteLine($"name:{p.Name} quantity: {p.Quantity}");
            }
        }

        public static int GetQuantity(int qty, int qtyTotal, int idx)
        {
            return Math.Max(Math.Min(qtyTotal - qty * idx, qty), 0);
        }
    }

}


0 commentaires

0
votes

Utilisez Math.DivRem méthode pour:

  1. Obtenez le quotient de total_item_quantity / people.Count et du reste.
  2. Obtenez le nombre de personnes qui recevront le partage.

Tout d'abord, revisitons la classe People .

Amount to share: 17
 Person 1, 6
 Person 2, 6
 Person 3, 5

Amount to share: 28
  Person 1, 4
  Person 2, 4
  Person 3, 4
  Person 4, 4
  Person 5, 4
  Person 6, 4
  Person 7, 4

Amount to share: 82
  Person 1, 14
  Person 2, 14
  Person 3, 14
  Person 4, 14
  Person 5, 13
  Person 6, 13

Il vaut mieux créer une méthode d'extension pour le IEnumerable pour distribuer les partages.

    static void Main()
    {
        var people = getPeopleFromDB();
        var total_item_quantity = getQuantityFromDB();

        people.Share(total_item_quantity);
        people.ForEach(x => Console.WriteLine(x));
    }
}

Maintenant, votre principal devrait être quelque chose comme ceci:

    static class Extensions
    {
        public static void Share(this IEnumerable<People> people, int amountToShare)
        {
            var div = Math.DivRem(amountToShare, people.Count(), out int rem);
            Math.DivRem(rem, people.Count(), out int maxPersons);

            people.Select((x, i) => {
                x.Quantity = div + (i < maxPersons ? 1 : 0); return x; }).ToList();
        }
    }

Voici les résultats de tests aléatoires:

namespace YourApp
{
    //...

    public class People
    {
        public string Name { get; set; } = string.Empty;
        public int Quantity { get; set; } = 0;

        public People() { }

        public People(string name) => this.Name = name;

        public People(string name, int quantity)
        {
            this.Name = name;
            this.Quantity = quantity;
        }

        public override string ToString() => $"{Name}, {Quantity}";
    }


1 commentaires

Wow, tt est vraiment intelligent. C # c'est un langage très puissant en effet Merci beaucoup, c'était presque une seule ligne. Marqué comme la solution. Merci.