开发者

Ensure uniqueness of data before creating object?

开发者 https://www.devze.com 2023-02-20 11:38 出处:网络
I have a file full of data that I need to operate on. Each line of this file contains floating point numbers (represented as strings of course) like this:

I have a file full of data that I need to operate on. Each line of this file contains floating point numbers (represented as strings of course) like this:

x1 y1 z1 x2 y2 z2 x3 y3 z3 r1 g1 b1 r2 g2 b2 r3 g3 b3

each line represents 3 different objects that I need to create, like:

Foo foo1(x1,y1,z1,r1,g1,b1);

Foo foo2(x2,y2,z2,r2,g2,b2);

Foo foo3(x3,y3,z3,r3,g3,b3);

the twist is that:

  1. I want to ONLY create objects if they haven't been created yet. if I've already made a Foo with those exact same 6 floats, instead of creating a new Foo I want to just retrieve that object I alr开发者_开发问答eady made.

  2. The data in the file is unreliably delimited -- there could be any number of spaces or tabs between the different numbers.

Before I realized this issue with the spacing, I was splitting each line I read from the file into strings, concatenating the strings that represented each foo, and then using a std::map<std::string,int> to test for uniqueness, where the int returned by the map represented an index into a std::vector<Foo*> that I was pushing pointers to each Foo I was creating into. This fails when the spacing isn't consistent.

all I can think of right now is doing something like: http://codepad.org/hLhFzhPh (for example) but that seems completely screwy. I also tried making a struct of 6 floating point values, overloading operator>> to read from a stringstream into it, and then making a map<weirdstruct,int> but I didn't really know how to overload operator< to make this work.

Anyway, this seems like it should be easy and I just don't have a clue. Any ideas?


1: Use an std::set<Foo> to record what you've already constructed. The std::map + std::vector solution is both unreliable and, when fixed, overkill.

2: The following skips over any leading spaces in the input:

double x;
std::cin >> x;

and similar for any std::istream.


I think I'd convert the inputs to real floating point before comparing. With floating point numbers, differences in the string representation don't necessarily signify differences in the actual value. Just for example, 12345 is equal to 1.2345e4.


Something like this if you just want a quick solution.

std::stringstream sIn(theline);
std::stringstream sOut;

std::string temp;

while (sIn >> temp) sOut << temp << " ";

std::string fixedline = sOut.str();


The problem I see is finding an exact match since you are using floating point numbers.

I suggest adding an operator==(x,y,z,r,g,b) to Foo. Place all your Foo objects into a container and compare them using the operator==(), to see if a Foo object has already been created.

An alternative method is to factor out the <x,y,z,r,g,b> into a parent structure. Create a container of these. When you create a Foo object, put an instance into the container. You can search the container before you create the next Foo instance.

I also suggest transposing the data file so that each line contains only one vector of x,y,z,r,g,b. Sort the file. Remove duplicates before giving it to your program. Use applications outside of your program to do this (preferred). Cygwin and Linux have some nice utilities for sorting and removing duplicates.

Edit1: Example 3D point with input operator (untested)

ifndef POINT3D_HPP
#include <iostream>
#include <cmath>

class Point3d
{
public:
    Point3d(double x = 0.0, double y = 0.0, double z = 0.0)
        : m_x(x), m_y(y), m_z(z)
        { ; }
    Point3d(const Point3d& p3d)
        : m_x(p3d.m_x), m_y(p3d.m_y), m_z(p3d.m_z)
        { ; }

    friend std::istream& operator>>(std::istream& inp, Point3d& p3d);

    bool operator==(const Point3d& p) const
        {
            return (std::fabs(m_x - p.m_x) < 5.0E-5)
                && (std::fabs(m_y - p.m_y) < 5.0E-5)
                && (std::fabs(m_z - p.m_z) < 5.0E-5);
        }

private:
    double m_x;
    double m_y;
    double m_z;
};

inline std::istream&
operator>>(std::istream& inp, Point3d& p)
{
    inp >> p.m_x;
    inp >> p.m_y;
    inp >> p.m_z;
    return inp;
}

#endif // POINT3D_HPP

class Foo
: public Point3d
{
public:
    Foo(double x, double y, double z,
        double r, double g, double b)
    : Point3d(x, y, z),
      m_r(r), m_g(g), m_b(b)
    { ; }

    Foo(const Point3d& p3d,
        double r, double g, double b)
    : Point3d(p3d),
      m_r(r), m_g(g), m_b(b)
    { ; }

    double m_r, m_g, m_b;
};

Reading of the data file becomes something like this:

  std::ifstream data_file("data.bin");
  Point3d p1;
  Point3d p2;
  Point3d p3;
  // Input the first 3 points on the line.
  data_file >> p1;
  data_file >> p2;
  data_file >> p3;
  // Or:  data_file >> p1 >> p2 >> p3

  // Before creating a Foo:
  std::vector<Point3d> existing_points;
  std::vector<Point3d>::const_iterator iter;
  bool is_duplicate = false;
  for (iter = existing_points.begin();
       iter != existing_points.end();
       ++iter)
  {
      if (*iter == p1)
      {
         is_duplicate = true;
         break;
      }
  }
  if (! is_duplicate)
  {
     existing_points.push_back(p1);
     // Create a new Foo
  }

The color values can be treated in a very similar fashion (so similar, you could just change member names and class names).

0

精彩评论

暂无评论...
验证码 换一张
取 消