Naloga: Oglasi

Naloga: Oglasi

Avtor: Gregor Šoln

Navodilo naloge in ideja rešitve

Oglasi

Na datoteki imamo zapisane podatke o časih predvajanja oglasnih sporočil na posameznih TV postajah v toku enega dne. V vsaki vrstici je zapis oblike oznaka_programa čas_začetka čas_konca Časi so zapisani v obliki hh:mm:ss v oznaki programama pa so lahko poljubni znaki (tudi presledki). Napiši program, ki prebere podatke z datoteke in poišče najdaljšega izmed intervalov, v katerem je največ televizijskih postaj hkrati predvajalo oglase.

Vnesi ime datoteke:
podatki.txt
Največ hkratnih oglasov: 3
Čas prevajanja: 18:55:23 - 18:58:10 na TV 99, Firbec TV in Q2Q

Ideja rešitve

Iz datoteke preberemo podatke o predvajanju oglasov na različnih televizijah. Med sabo primerjamo čase začetkov in čase konec. Če se oglasa na različnih televizijah predvajata vsaj delno v istem časovnem intervalu, vemo da se oglasa prekrivata. Na koncu izpišemo čas predvajanja oglasa in televizije na katerih se oglas predvaja.

Postopek iskanja skupnega intervala

Informacije o predvajanju reklam z različnih tv-postaj preberemo iz datoteke, kjer je v vsaki vrstici zapisano ime postaje, ter začetek in konec reklame. Z metodo SkupniInterval(string imeDat) izluščimo skupne intervale reklam. Kako ugotovimo ali se reklame med seboj prekrivajo, si bomo ogledali v nadaljevanju. Vsebino iz datoteke shranimo v slovar, kjer je ključ ime postaje, vrednosti pa so začetek in konec predvajanja reklame. Z dvojno zanko s sprehodimo po slovarju in predelamo vse možnosti med sabo. S pomočjo metod ZacVecji in KonecManjsi ugotovimo ali se katera reklama začne preden se je ta ista na drugi televizijski postaji končala. Na kratko, tukaj ugotovimo ali obstajajo morebitni skupni intervali predvajanja.
Če se pojavijo kakšne televizijske postaje, ki istočasno predvajajo reklamo, si jih zapomnemo tako, da jih shranimo v slovar skupniInt , kjer z vgrajeno funkcijo Add , dodamo zapis v slovar.

                        if (ZacVecji(zacetekPrim, zacetek) && KonecManjsi(konecPrim, konec))
                        {
                            ime += "_" + imePrim;
                            zacetek = zacetekPrim;
                            konec = konecPrim;
                        }

Seveda pa nas zanima najdaljši interval, ki se je zgodil. S pomočjo metode PoisciNajdaljsega(skupniInt) bomo poiskali najdaljši interval, ki smo ga prej izluščili iz podatkov. Pred tem si bomo ogledali metodo, ki izlušči skupni interval in nato si bomo ogledali še metodo, ki poišče najdaljši skupni interval.

Podrobnosti


public static string[] SkupniInterval(string imeDat)
        {
            Dictionary<string, string[]> sezInt = PreberiDat(imeDat); //seznam vseh reklam
            Dictionary<string, string[]> skupniInt = new Dictionary<string, string[]>();
            foreach (var intReklam in sezInt) //uporabim dvojno zanko saj tako "predelamo" vse možnosti
            {
                string ime = intReklam.Key;
                string zacetek = intReklam.Value[0];
                string konec = intReklam.Value[1];
                foreach (var primerjaj in sezInt)
                {
                    string imePrim = primerjaj.Key;
                    string zacetekPrim = primerjaj.Value[0];
                    string konecPrim = primerjaj.Value[1];
                    if (!ime.Contains(imePrim)) //v istem intervalu se ne more ista postaja večkrat ponoviti
                    {
                        if (ZacVecji(zacetekPrim, zacetek) && KonecManjsi(konecPrim, konec))
                        {
                            ime += "_" + imePrim;
                            zacetek = zacetekPrim;
                            konec = konecPrim;
                        }
                    }
                }
                skupniInt.Add(ime, new string[2] { zacetek, konec });
            }
            return PoisciNajdaljsega(skupniInt); //želimo poiskati najdaljši interval

        }

Zapri

Skupni interval

Metoda ZacVecji preveri ali se druga reklama začne še preden se prva konča. Metoda prejme dva parametra, začetka reklam na dveh različnih tv-postajah. Zapis o času ki je oblike 00:00:00 razdelimo z metodo Split in izluščimo za katere podatke gre. Nato najprej preverimo uro, ali se druga reklama začne že pred prvo. Na enak princip kot se preveri interval za uro se preveri interval za minute in sekunde. Torej, če želimo da najdemo skupni interval moramo čas pričetka druge oddaje primerjati s časom prve. In če se drug čas začne pred prvim oz. je manjši, potem tukaj obstaja skupni interval, ki si ga zapomnemo. Torej če gre za kakšen skupen interval metoda vrne vrednost True sicer pa False . S to metodo samo ugotavljamo ali obstaja skupni interval zato ne vrača nobenih drugih verdnosti.

V nadaljevanju si bomo ogledali še dve metodi, s katerima poiščemo interval, ki je najdaljši.

Podrobnosti


        /// <summary>
        /// preveri ali se drugi interval začne po začetku prvega
        /// </summary>
        /// <param name="prviZac">prvi interval</param>
        /// <param name="drugiZac">drugi interval</param>
        /// <returns>true ali false</returns>
        private static bool ZacVecji(string prviZac,string drugiZac )
        {
            string[] razdeliPrviZac = prviZac.Split(':'); //za lažje primerjanje niz razdelimo na ure, minute in sekunde
            string[] razdeliDrugiZac = drugiZac.Split(':');
            if (int.Parse(razdeliPrviZac[0]) < int.Parse(razdeliDrugiZac[0]))
                return false;
            if (int.Parse(razdeliPrviZac[0]) > int.Parse(razdeliDrugiZac[0]))
                return true;
            else
            {
                if (int.Parse(razdeliPrviZac[1]) < int.Parse(razdeliDrugiZac[1]))
                    return false;
                if (int.Parse(razdeliPrviZac[1]) > int.Parse(razdeliDrugiZac[1]))
                    return true;
                else
                {
                    if (int.Parse(razdeliPrviZac[1]) < int.Parse(razdeliDrugiZac[1]))
                    return false;

                }
            }
            return true;
        }
        /// <summary>
        /// preveri ali se drugi interval konča pred prvim
        /// </summary>
        /// <param name="prviKon">prvi interval</param>
        /// <param name="drugiKon">drugi interval</param>
        /// <returns></returns>
        private static bool KonecManjsi(string prviKon, string drugiKon)
        {
            string[] razdeliPrviZac = prviKon.Split(':');
            string[] razdeliDrugiZac = drugiKon.Split(':');
            if (int.Parse(razdeliPrviZac[0]) > int.Parse(razdeliDrugiZac[0]))
                return false;
            if (int.Parse(razdeliPrviZac[0]) < int.Parse(razdeliDrugiZac[0]))
                return true;
            else
            {
                if (int.Parse(razdeliPrviZac[1]) > int.Parse(razdeliDrugiZac[1]))
                    return false;
                if (int.Parse(razdeliPrviZac[1]) < int.Parse(razdeliDrugiZac[1]))
                    return true;
                else
                {
                    if (int.Parse(razdeliPrviZac[1]) > int.Parse(razdeliDrugiZac[1]))
                        return false;

                }
            }
            return true;

        }

Zapri

Najdaljši skupni interval

Sedaj, ko smo poiskali vse skupne intervale predvajanja oglasov na različnih tv-postajah, je poterbno poiskati najdaljše intervale, ki obstajajo. Kako to storimo? Metoda DolzinaIntervala bo skrbela, da trajanje intervalov pretvorimo v sekunde, saj bomo tako najlažje preverili, kateri interval je najdaljši. Intervale, ki smo jih prej poiskali smo shranili v slovar skupniInt . Metoda, ki je tukaj ključnega pomena je metoda poisciNajdaljsega .


            foreach (var interval in sezInt) //iskalna zanka
            {
                if (interval.Key.Split('_').Length > najvecProg)
                    if (najvecProg == 0 || (DolzinaIntervala(interval.Value[0], interval.Value[1]) > DolzinaIntervala(zacMaks, konMaks)))
                    {
                        ime = interval.Key;
                        zacMaks = interval.Value[0];
                        konMaks = interval.Value[1];
                    }


            }
            return new string[3] { ime, zacMaks, konMaks }
Zgornji primer prikazuje kako se s foreach zanko sprehodimo po celotnem slovarju skupnih intervalov. Tukaj v vsakem koraku pokličemo prej omenjeno metodo, ki časovne intervale pretvori v sekunde. Preveri se ali je morebiti trenutni (že znan najdaljši interval) res najdaljši. Če se najde kak daljši, si zapomnemo njegovor ime ter začetek in konec intervala. Te podatke vrnemo v obliki seznama nizov.


Metodi DolzinaIntervala in poisciNajdaljsega

Podrobnosti


 /// <summary>
        /// Vrne dolžino enega intervala v sekundah
        /// </summary>
        /// <param name="zacetek">začetek intervala</param>
        /// <param name="konec">konec intervala</param>
        /// <returns>dolžina intervala v sekundah</returns>
        private static int DolzinaIntervala(string zacetek,string konec)
        {
            string[] razdeliZac = zacetek.Split(':');
            string[] razdeliKon = konec.Split(':');
            int dolzina = 0;
            int razlikaUre = int.Parse(razdeliKon[0])-int.Parse(razdeliZac[0]);
            dolzina += razlikaUre*3600;
            int razlikaMin = int.Parse(razdeliKon[1])-int.Parse(razdeliZac[1]);
            dolzina += razlikaMin * 60;
            int razlikaSec = int.Parse(razdeliKon[2])-int.Parse(razdeliZac[2]);
            dolzina += razlikaSec;
            return dolzina;

        }
        /// <summary>
        /// vrne najdaljši skupni interval in imena postaj, ki predvajajo reklame
        /// </summary>
        /// <param name="sezInt">vsi skupni intervali</param>
        /// <returns>najdaljši interval in imena postaj</returns>
        public static string[] PoisciNajdaljsega(Dictionary<string,string[]> sezInt)
        {
            int najvecProg = 0;
            string ime = "";
            string zacMaks = "";
            string konMaks = "";
            foreach (var interval in sezInt) //iskalna zanka
            {
                if (interval.Key.Split('_').Length > najvecProg)
                    if (najvecProg == 0 || (DolzinaIntervala(interval.Value[0], interval.Value[1]) > DolzinaIntervala(zacMaks, konMaks)))
                    {
                        ime = interval.Key;
                        zacMaks = interval.Value[0];
                        konMaks = interval.Value[1];
                    }


            }
            return new string[3] { ime, zacMaks, konMaks }; //vrne seznam v katerem je ime postaje, začetni čas reklam in končni čas reklam


        }

Zapri

Testni primer

Najprej sestavimo testni program, s pomočjo katerega bomo uporabili do sedaj napisane metode.


class Program
    {
        static void Main(string[] args)
        {
            //preberemo ime datoteke s vsebino
            Console.Write("Vnesi ime datoteke: ");
            string imeDat = Console.ReadLine();

            //poiščemo skupni interval
            string[] rezSkupni = metode.SkupniInterval(imeDat);
            string[] razdeliIme = rezSkupni[0].Split('_'); //lepši izpis
            Console.WriteLine("Največ hkratnih oglasov: " + razdeliIme.Length);
            Console.WriteLine("Čas predvajanja: " + rezSkupni[1] + " - " + rezSkupni[2] + " na " + metode.izpisVseh(razdeliIme));
            Console.ReadLine();
        }
    }

  • Najprej bomo iz datoteke prebrali imena tv-postaj in časovne intervale oglasov, ki se predvajajo.
  • V nadaljevanju pokličemo metodo SkupniInterval , ki najprej poišče skupne intervale predvajanja in nato izlušči najdaljše intervale. Dobljene podatke izpišemo v pregledni obliki: ime_postaje čas_začetka čas_konca .

Kakšne podatke bomo uporabili?

(podatki.png)
Podatke o tv-postajah in terminih predvajanja shranimo v tekstovno datoteko.

Program

Na teh povezavah si lahko prenesete kodo metod in testnega programa, ki smo ga spoznali na prosojnicah.

Program.cs Metode.cs

0%
0%