Luis Alvarado
Luis Alvarado

Reputation: 9406

Read, Search & Sort all CSV values without the dupes

I have the following CSV:

Title, Rating, Year, Genre
All Quiet on the Western Front,8.1,1930,"Drama , War"
Gone with the Wind,8.2,1939,"Drama , Romance , War"
The Wizard of Oz,8.2,1939,"Adventure , Family , Fantasy , Musical"
Fantasia,7.9,1940,"Animation , Family , Fantasy , Music"
Pinocchio,7.6,1940,"Animation , Adventure , Drama , Family , Fantasy , Music"
The Great Dictator,8.5,1940,"Comedy , Drama , War"
Citizen Kane,8.5,1941,"Drama , Mystery"
Dumbo,7.3,1941,"Animation , Family , Musical"
Bambi,7.4,1942,"Animation , Drama , Family"
Casablanca,8.7,1942,"Drama , Romance , War"
It's a Wonderful Life,8.7,1946,"Drama , Family , Fantasy"
Notorious,8.2,1946,"Drama , Film-Noir , Romance , Thriller"
All About Eve,8.4,1950,Drama
Cinderella,7.3,1950,"Animation , Family , Fantasy , Musical , Romance"
Alice in Wonderland,7.4,1951,"Animation , Adventure , Family , Fantasy , Musical"
Strangers on a Train,8.2,1951,"Crime , Film-Noir , Thriller"
Dial M for Murder,8.2,1954,"Crime , Thriller"
Knock on Wood,7,1954,Comedy
Seven Samurai,8.8,1954,"Action , Drama"
Lady and the Tramp,7.4,1955,"Animation , Adventure , Comedy , Family , Romance"
Rebel Without a Cause,7.8,1955,"Drama , Romance"
The Trouble with Harry,7.2,1955,"Comedy , Mystery"
Forbidden Planet,7.7,1956,"Action , Adventure , Sci-Fi"
The Ten Commandments,7.9,1956,"Adventure , Drama , History"
12 Angry Men,8.9,1957,Drama

What I am trying to accomplish is this (My head is not working correctly right now):

Read the CSV and create an array that only shows all unique Genre (eg: Drama, War, Fantasy.. without repeating the Genre in the array)

Search the CSV for rows that have a specific Genre. For example, if I search for Drama, only rows that have the Drama value in the 4th column will be shown. (without showing the Genre column)

Sort the CSV by either Title, Rating or Year (without showing the Genre column).

I am reading the CSV in the following way:

$.ajax({
        type: "GET",
        url: "movies.csv",
        dataType: "text",
        success: function(data) {
            var results = $.parse(data);
        }
     });

If I do a alert(JSON.stringify(results, null, 4)) it will print the correct information. The JSON Object looks like this:

{
  "results": {
    "fields": [
      "Title",
      " Rating",
      " Year",
      " Genre"
    ],
    "rows": [
      {
        "Title": "All Quiet on the Western Front",
        " Rating": 8.1,
        " Year": 1930,
        " Genre": "Drama , War"
      },
      {
        "Title": "Gone with the Wind",
        " Rating": 8.2,
        " Year": 1939,
        " Genre": "Drama , Romance , War"
      },
      {
        "Title": "The Wizard of Oz",
        " Rating": 8.2,
        " Year": 1939,
        " Genre": "Adventure , Family , Fantasy , Musical"
      },
      {
        "Title": "Fantasia",
        " Rating": 7.9,
        " Year": 1940,
        " Genre": "Animation , Family , Fantasy , Music"

So I know that part is working. I am trying to create an array and then fill a SELECT tag with the Genre values. Then if the user selects one of them, it will search the file again but only showing the rows that have the Genre specify. The user will be able to sort the list by the 3 first columns. My asking right now since my head (and eyesight) is not working very good right now.

Upvotes: 0

Views: 403

Answers (2)

coma
coma

Reputation: 16659

The genre select

http://jsfiddle.net/coma/4N676/25/

var movies = new Movies(JSON.parse(gists.files.Movies.content));
var html = '<option>Filter by genre</option>';

movies.getGenres().forEach(function(genre) {

    html += '<option value="' + genre + '">' + genre + '</option>';
});

$('#genre')
    .html(html)
    .change(function() {

        var list = movies
            .reset()
            .filterByGenre(this.value)
            .sortByTitleAsc()
            .getList();

        alert(JSON.stringify(list));
    });

http://jsfiddle.net/coma/4N676/

Base

var Movies = function(movies)
{
    var genres = [];
    var ratingMin = Infinity;
    var ratingMax = -1;
    var yearMin = Infinity;
    var yearMax = -1;

    movies.forEach(function(movie, movieIndex) {

        movie.Genre  = movie.Genre.split(', ');
        movie.Rating = parseFloat(movie.Rating);
        movie.Year = parseInt(movie.Year, 10);

        ratingMin = Math.min(movie.Rating, ratingMin);
        ratingMax = Math.max(movie.Rating, ratingMax);

        yearMin = Math.min(movie.Year, yearMin);
        yearMax = Math.max(movie.Year, yearMax);

        movie.Genre.forEach(function(genre, genreIndex) {

            genre = $.trim(genre).toLowerCase();
            movie.Genre[genreIndex] = genre;

            if (genres.indexOf(genre) < 0) {

                genres.push(genre);
            }

            genres.sort();
        });
    });

    this.original  = movies;
    this.list      = movies.slice();
    this.ratingMin = ratingMin;
    this.ratingMax = ratingMax;
    this.yearMin   = yearMin;
    this.yearMax   = yearMax;
    this.genres    = genres;
};

Movies.prototype.reset = function()
{
    this.list = this.original.slice();

    return this;
};

Getters

Movies.prototype.getList = function()
{
    return this.list.slice();
};

Movies.prototype.getRatingRange = function()
{
    return [this.ratingMin, this.ratingMax];
};

Movies.prototype.getRatingMax = function()
{
    return this.ratingMax;
};

Movies.prototype.getRatingMin = function()
{
    return this.ratingMin;
};

Movies.prototype.getYearRange = function()
{
    return [this.yearMin, this.yearMax];
};

Movies.prototype.getYearMax = function()
{
    return this.yearMax;
};

Movies.prototype.getYearMin = function()
{
    return this.yearMin;
};

Movies.prototype.getGenres = function()
{
    return this.genres.slice();
};

Filters

Movies.prototype.filterByNumbers = function(property, number)
{
    if ($.isNumeric(number)) {

        this.list = this.list.filter(function(movie) {

            return movie[property] === number;
        });
    }

    if ($.isArray(number)) {

        this.list = this.list.filter(function(movie) {

            return movie[property] >= number[0]
                && movie[property] <= number[1];
        });
    }

    return this;
};

Movies.prototype.filterByGenre = function(genre)
{
    this.list = this.list.filter(function(movie) {

        return movie
            .Genre
            .indexOf(genre.toLowerCase()) >= 0;
    });

    return this;
};

Movies.prototype.filterByTitle = function(title)
{
    this.list = this.list.filter(function(movie) {

        return movie
            .Title
            .toLowerCase()
            .indexOf(title.toLowerCase()) >= 0;
    });

    return this;
};

Movies.prototype.filterByYear = function(year)
{ 
    this.filterByNumbers('Year', year);

    return this;
};

Movies.prototype.filterByRating = function(rating)
{ 
    this.filterByNumbers('Rating', rating);

    return this;
};

Sorters

Movies.prototype.sortAsc = function(property)
{ 
    this.list.sort(function(a, b) {

        return a[property] > b[property];
    });

    return this;
};

Movies.prototype.sortDesc = function(property)
{ 
    this.list.sort(function(a, b) {

        return a[property] < b[property];
    });

    return this;
};

Movies.prototype.sortByTitleAsc = function()
{ 
    this.sortAsc('Title');

    return this;
};

Movies.prototype.sortByTitleDesc = function()
{ 
    this.sortDesc('Title');

    return this;
};

Movies.prototype.sortByYearAsc = function()
{ 
    this.sortAsc('Year');

    return this;
};

Movies.prototype.sortByYearDesc = function()
{ 
    this.sortDesc('Year');

    return this;
};

Movies.prototype.sortByRatingAsc = function()
{ 
    this.sortAsc('Rating');

    return this;
};

Movies.prototype.sortByRatingDesc = function()
{ 
    this.sortDesc('Rating');

    return this;
};

Usage

$.getJSON('https://api.github.com/gists/9803182', function(gists) {

    var movies = new Movies(JSON.parse(gists.files.Movies.content));

    movies
        .filterByGenre('comedy')
        .filterByYear([1954, 2000])
        .sortByTitleDesc();

    console.log('Filtered and sorted', movies.getList());
    console.log('Original', movies.reset().getList());
});

Upvotes: 1

Gautam Bhutani
Gautam Bhutani

Reputation: 405

Ok, here it goes.

You can parse your JSON and traverse through it one by one. You would need to have a parent object which would keep your final rows vs. genre values.

The parent object would look something like this:

var myObject = {
genre : {records: []}
}

This will contain genre to records mapping.

While traversing the JSON object, if you find the genre already in your 'myObject', just push the record. If not, create the 'genre' and then push it.

Something like the below.

//Initialize my variables - Note, I'm using my own JSON
var objectArray = JSON.parse('[{"title":"title1","name":"name1","genre":"genre1"},{"title":"title2","name":"name2","genre":"genre2"},{"title":"title3","name":"name3","genre":"genre1"}]'),
counter=0,myObject={};

for (count=0; counter<objectArray.length; counter++) {
    var individualRecord=objectArray[counter];
    if(myObject[individualRecord.genre] === undefined) {
        console.log('creating object');
        myObject[individualRecord.genre]={records : []};
    }
    console.log('adding individual record');
    myObject[individualRecord.genre].records.push(individualRecord);
}

console.log(myObject) will give you:

genre1 - Array with 2 elements
genre2 - Array with 1 element

Post this if you want to retrieve elements for a particular genre, you could just do this:

myObject["genre1"] - to handle dynamic genres

OR 

myObject.genre1 - to explicitly fetch the value of the variable

Once you have the data stored in this format, you would not need to read the file again. You can filter based on myObject["<filter 1>"], etc..

Hope this helps!

Upvotes: 1

Related Questions