Giter Club home page Giter Club logo

boolinq's Introduction

boolinq 3.0

CI Status Coverage Status

Super tiny C++11 single-file header-only LINQ template library

Just imagine .NET Framework LINQ support for STL/Qt collections :)

Get source code here: boolinq.h

Wanna demo?

Example with integers

int src[] = {1,2,3,4,5,6,7,8};
auto dst = from(src).where( [](int a) { return a % 2 == 1; })      // 1,3,5,7
                    .select([](int a) { return a * 2; })           // 2,6,10,14
                    .where( [](int a) { return a > 2 && a < 12; }) // 6,10
                    .toStdVector();

// dst type: std::vector<int>
// dst items: 6,10

Example with structs

struct Man {
    std::string name;
    int age;
};

Man src[] = {
    {"Kevin",14},
    {"Anton",18},
    {"Agata",17},
    {"Terra",20},
    {"Layer",15},
};

auto dst = from(src).where(  [](const Man & man) { return man.age < 18; })
                    .orderBy([](const Man & man) { return man.age; })
                    .select( [](const Man & man) { return man.name; })
                    .toStdVector();

// dst type: std::vector<std::string>
// dst items: "Kevin", "Layer", "Agata"

Interesting example

struct Message {
    std::string PhoneA;
    std::string PhoneB;
    std::string Text;
};

Message messages[] = {
    {"Anton","Troll","Hello, friend!"},
    {"Denis","Wride","OLOLO"},
    {"Anton","Papay","WTF?"},
    {"Denis","Maloy","How r u?"},
    {"Denis","Wride","Param-pareram!"},
};

int DenisUniqueContactCount =
    from(messages).where(   [](const Message & msg) { return msg.PhoneA == "Denis"; })
                  .distinct([](const Message & msg) { return msg.PhoneB; })
                  .count();

// DenisUniqueContactCount == 2    

Test in C++14 using auto

The following test requires C++14 GroupByTestComplex.cpp It uses auto in order to avoid a very long lambda argument type. The return type of a function or lambda expression can be deduced by its operand since C++14. The CMake file is changed so that this test runs with C++14.

TEST(GroupBy, CountTaxes)
{
    struct Tax {
        std::string name;
        int amount_1;
        int amount_2;

        bool operator ==(const Tax & tax) const {
            return name == tax.name
                && amount_1 == tax.amount_1
                && amount_2 == tax.amount_2;
        }
    };

    std::vector<Tax> taxes = {
        {"tax 1", 1, 1},
        {"tax 2", 1, 1},
        {"tax 1", 2, 2},
        {"tax 3", 3, 3},
        {"tax 1", 4, 4},
    };

    Tax ans[] = {
        {"tax 1", 7, 7},
        {"tax 2", 1, 1},
        {"tax 3", 3, 3},
    };

    auto dst = from(taxes)
        .groupBy([](const Tax & a){return a.name;})
        .select([](const auto & pair){ // use of auto here needs c++14
            return Tax {
                pair.first,
                pair.second.sum([](const Tax & a){return a.amount_1;}),
                pair.second.sum([](const Tax & a){return a.amount_2;})
            };
        });

    CheckRangeEqArray(dst, ans);
}

Containers supported?

  • C++: Native arrays, pairs of pointers
  • STL: list, stack, queue, vector, deque, set, map, any compatible ....
  • Qt: QList, QVector, QSet, QMap.

Operators supported?

Filters and reorders:

  • where(predicate), where_i(predicate)
  • take(count), takeWhile(predicate), takeWhile_i(predicate)
  • skip(count), skipWhile(predicate), skipWhile_i(predicate)
  • orderBy(), orderBy(transform)
  • distinct(), distinct(transform)
  • append(items), prepend(items)
  • concat(linq)
  • reverse()
  • cast<T>()

Transformers:

  • select(transform), select_i(transform)
  • groupBy(transform)
  • selectMany(transfom)

Aggregators:

  • all(), all(predicate)
  • any(), any(lambda)
  • sum(), sum<T>(), sum(lambda)
  • avg(), avg<T>(), avg(lambda)
  • min(), min(lambda)
  • max(), max(lambda)
  • count(), count(value), count(predicate)
  • contains(value)
  • elementAt(index)
  • first(), first(filter), firstOrDefault(), firstOrDefault(filter)
  • last(), last(filter), lastOrDefault(), lastOrDefault(filter)
  • toStdSet(), toStdList(), toStdDeque(), toStdVector()

Bits and Bytes:

  • bytes<T>(ByteDirection?)
  • unbytes<T>(ByteDirection?)
  • bits(BitsDirection?, BytesDirection?)
  • unbits<T = unsigned char>(BitsDirection?, BytesDirection?)

Coming soon:

  • gz()
  • ungz()
  • leftJoin
  • rightJoin
  • crossJoin
  • fullJoin

boolinq's People

Contributors

babelvit avatar gluttton avatar helr441 avatar jell0nek avatar k06a avatar mmalcolm avatar nargeslein avatar neilharan avatar parallaxe avatar roquedeicide avatar taezstkyoht avatar theosch avatar theosch2 avatar xav83 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

boolinq's Issues

Copying of the provided containers in `boolinq::from`

If I correctly read the code – all the versions of boolinq::from copy provided container to the TC field of the IteratorContainerPair. Is this design intentional? Because it could be rather expensive on large collections.

Also, won't simple code like this do:

template <typename Container>
LinqObject<... smth. with decltype(std::begin(containter) ...> from(
         const Container& container) {
    return from(std::begin(container), std::end(container));
}

?

[Discussion] CI/CD Pipeline

Current CI/CD Pipeline

The current project simply uses TravisCI to run builds and tests for all PRs and branches in this repository. As defined in the current .travis.yml, all builds take place in a single environment:

  • Arch: X64 | OS: Ubuntu 16.04.7 LTS (Xenial Xerus)

This environment is used to build boolinq with the following compilers:

  • clang (v3.8)
  • g++ (v5-v9)
  • gcc (v5-v9)

Next Steps

Tracked by Issues: #64 & #63, efforts are being made to support the windows C++ compiler msvc, add the AppVeyor CI tool and build with different C++ standards. These changes to the project require a closer look at the entire CI/CD pipeline, as questions remain unclear:

  • "Which CI tool should run which OS?"
  • "What type of architectures should be supported?"
  • "How should builds be tracked in GitHub?"

This issue may act as a medium for discussion regarding questions and proposals to the CI/CD pipeline of this project.

compile failed

Hello.

With c++11 there is an compile error. Adding "#include <algorithm>" error disappeared.
Could you add this header include?

In file included from /home/nickfox/Desktop/jfxrender/include/jfxmaterial.h:8:0,
                 from /home/nickfox/Desktop/jfxrender/src/jfxmaterial.cpp:1:
/home/nickfox/Desktop/jfxrender/submodule/boolinq/include/boolinq/boolinq.h: In member function ‘boolinq::Linq<std::tuple<std::vector<T, std::allocator<_T2> >, _TIter, bool>, T> boolinq::Linq<S, T>::orderBy(F) const’:
/home/nickfox/Desktop/jfxrender/submodule/boolinq/include/boolinq/boolinq.h:337:18: error: ‘sort’ is not a member of ‘std’
             std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) {
                  ^~~~
/home/nickfox/Desktop/jfxrender/submodule/boolinq/include/boolinq/boolinq.h:337:18: note: suggested alternative: ‘set’
             std::sort(items.begin(), items.end(), [transform](const T &a, const T &b) {
                  ^~~~
                  set

no instance of function template "boolinq::Linq<S, T>::select

Hello there,
first of all, I have a big compliment to offer. Wonderful work. 👍

I wanted to use boolinq on my current platform.io esp32 project. However, I always get the following error when using select:

no instance of function template "boolinq::Linq<S, T>::select [with S=std::tuple<boolinq::Linq<std::pair<const int *, const int *>, int>, int>, T=int]" matches the argument list -- argument types are: (lambda []int (int a)->int) -- object type is: boolinq::Linq<std::tuple<boolinq::Linq<std::pair<const int *, const int *>, int>, int>, int>

Using the example from the readme.

using namespace boolinq;

int src[] = {1, 2, 3, 4, 5, 6, 7, 8};
auto dst = from(src).where([](int a) { return a % 2 == 1; })      // 1,3,5,7
                    .select([](int a) { return a * 2; })          // 2,6,10,14
                    .where([](int a) { return a > 2 && a < 12; }) // 6,10
                    .toStdVector();

is this due to the compiler used by platform.io? Do I have to include the file differently?

Thanks for your help.
Greetings
Ruffo

Configure one of the tests to use C++14

This select lambda argument type in this test looks insane:

auto dst = from(taxes)
.groupBy([](const Tax & a){return a.name;})
.select([](const std::pair<std::string, Linq<std::tuple<Linq<std::pair<std::vector<Tax>::const_iterator, std::vector<Tax>::const_iterator>, Tax>, int>, Tax> > & pair){ // const std::pair<std::string, Linq<Tax> > &
return Tax {
pair.first,
pair.second.sum([](const Tax & a){return a.amount_1;}),
pair.second.sum([](const Tax & a){return a.amount_2;})
};
});

  1. Extract this test to separate target test14 (create it) or something and configure it to use C++14 and use auto instead of this long type.
  2. Add this example to README, specify that C++14 is required to use auto here.

Reorganize the project structure.

I propose to reorganize the project structure.

From:

..
|__benchmark
|
|__boolinq
   |__*Test.cpp
   |__SpeedTest.cpp
   |__boolinq.h

To something like (for instance):

..
|__externals            (Third party tools)
|  |__benchmark
|
|__test                 (Test suites)
|  |__*Test.cpp
|
|__include              (Source code)
|  |__boolinq
|     |__boolinq.h
|
|__benchmark            (Benchmarks)
   |__SpeedTest.cpp

The main idea is make tests, benchmarks and source code separate.

Example appears to crash on MSVC 2017

I've been using C# and LINQ for years, so this library looks just fantastic, as I am using C++ now and really miss how expressive C# is.

I run this example code:

int src[] = {1,2,3,4,5,6,7,8};
std::vector<int> dst = boolinq::from(src)
    .where([](int a) { return a % 2 == 1; }) // 1,3,5,7
    .select([](int a) { return a * 2; }) // 2,6,10,14
    .where([](int a) { return a > 2 && a < 12; }) // 6,10
    .toStdVector();

I get an exception in this function:

////////////////////////////////////////////////////////////////
// Linq Creators
////////////////////////////////////////////////////////////////

template<typename T>
Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type> from(const T & begin, const T & end)
{
    return Linq<std::pair<T, T>, typename std::iterator_traits<T>::value_type>(
        std::make_pair(begin, end),
        [](std::pair<T, T> &pair) {
            if (pair.first == pair.second) {
                throw LinqEndException();
            }
            return *(pair.first++);
        }
    );
}

The exception is on this line:

return *(pair.first++);

The exception is:

Exception thrown at 0x00007FFB4A13A388 in DemoRange.exe: Microsoft C++ exception: boolinq::LinqEndException at memory location 0x000000807813CCF4.

Environments tried in:

MSVC 2017 15.9.16 + MSVC with "ISO C++17 Standard (/std:c++17)"
MSVC 2017 15.9.16 + Intel Compiler v19.0 

Warnings during compilation

boolinq.h:67: Warning: C4100: 'index': unreferenced formal parameter

Here is source code, pls fix. Also, there are some other unreferences local variables/parameters which also produce these warnings.

        void for_each(std::function<void(T)> apply) const
        {
            return for_each_i([apply](T value, int index) { return apply(value); });
        }

Как IEnumerable

Привет. Нет возможности проверить, но очень интересно.

В примерах увидел, что везде цепочка вызовов заканчивается toVector to...

А можно написать как то так

for(auto&& i : from({1,2,3})
.where([] (auto&& i) {
return i % 2 == 0;
}))
Что то делаем...

auto enumerable = from(...).where(...)
Не будет вычисляться до того момента пока не сделаем функцию to...? Или не начнём итертровать? Как в дот нет? Спасибо

SelectMany

Hi,

How can I selectMany with objects? For example:

auto concatInnerList =
    from(*myObj)
        .selectMany([](const MyObj& myObjTemp) { return myObjTemp.innerList; })
        .toStdArray();

myObj is a std::vector<MyObject> which contains an inner list object std::vector.

Custom containers

Is there a list of requirements to make custom containers compatible with this library? I've implemented (c)begin/(c)end and most of everything I need for stl compatibility but don't know what boolinq requires.

about groupBy

std::vector<Man> src = {
		{"Kevin", 14}, {"Kevin", 24}, {"Kevin", 34}, {"Kevin", 44},
		{"Anton", 18},
		{"Terra", 20}, {"Terra", 21},
                {"Layer", 15},
                {"Agata", 17}, 
	};
    
	auto gr = boolinq::from(src1)
				  .groupBy([](Man a) {
					  return a.name;
				  })
				  .select([](auto p) {
					  return p.first + " => " + std::to_string(p.second.sum([](Man man) {
								 return man.age;
							 }));
				  }).toStdSet();

	for (auto& r : gr) {
		std::cout << r << std::endl;
	}

output:
 Kevin => 116

Unused variables

../../../rssguard/src/librssguard/3rd-party/boolinq/boolinq.h:120:38: warning: unused parameter 'value' [-Wunused-parameter]
            return where_i([count](T value, int i) { return i >= count; });
                                     ^
../../../rssguard/src/librssguard/3rd-party/boolinq/boolinq.h:282:54: warning: unused parameter 'index' [-Wunused-parameter]
            return selectMany_i([apply](T value, int index) { return apply(value); });
                                                     ^
../../../rssguard/src/librssguard/3rd-party/boolinq/boolinq.h:682:27: warning: unused variable 'index' [-Wunused-variable]
                     int &index = std::get<2>(tuple);
                          ^
../../../rssguard/src/librssguard/3rd-party/boolinq/boolinq.h:744:27: warning: unused variable 'index' [-Wunused-variable]
                     int &index = std::get<3>(tuple);

Query with avg and group by

Is it possible to groupBy, and then return the average for each group?

for example, this SQL query?

SELECT name, day, avg(time_on_phone) FROM data
GROUP BY name, day;

Option to give default value to firstOrDefault()

It would be great to be able to give an actual value to firstOrDefault to return when there is no first element. Right now it returns T(), which is not always desirable, and it would be great if there was an overload that takes a T&& or T const& and returns that instead.

C++ 20 Windows Build Problem

I am using your library. It could be built with C++ 17. But now I've changed my projects to be built with C++ 20 and it gives errors. Simple example error is like that:

int main() {
	vector<int> asd = { 3, 4, 1, -1, 565 };
	for (int b : from(asd).where([](int a) { return a > 3; }).toStdVector())
		cout << b << endl;

	return 0;
}
Severity	Code	Description	Project	File	Line	Suppression State
Error (active)	E0135	class "boolinq::Linq<std::tuple<boolinq::Linq<std::pair<std::_Vector_const_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types<int>, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>, std::_Vector_const_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types<int>, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>>, int>, int>, int>" has no member "toStdVector"

Non-copyable types of elements are not supported

This will not work:

std::vector<std::unique_ptr<MyType>> myVector;
boolinq::from(xmlLogicFragments)
    .select([](const auto& uniquePtr) { return uniquePtr.get(); })
    .toVector();

I.e. conversion from the vector of the unique ptrs to the vector of raw ptrs does not work.
The vector of unique ptrs is convenient to have RAII for the collection of items, as it is suggested e.g. here http://stackoverflow.com/questions/27460377/why-is-using-vector-of-pointers-considered-bad

Also there are possible the other situations, when non-copyable elements can be used.

Would that be possible if boolinq is working with the references to the elements in such cases instead?

toMap() function is missing; would like to offer my implementation

Hello,

Since this states it supports the map stl container type, and if this is supposed to mimic C# Linq, then I think its reasonable to expect that there should be a ToDictionary() equivalent (toMap() for C++/boolinq).

I don't fully understand C++ templates (does anyone, really?) but I was able to put together a basic implementation. The implementation takes two selector functions, one for key, another for value, just like Linq's ToDictionary( ) in C#.

Implementation code:

#include <map>   //remember to include map

template<typename F, typename _FRet = typename priv::result_of<F(T)>::type,
              typename G, typename _GRet = typename priv::result_of<G(T)>::type>
     std::map<_FRet, _GRet> toMap(F keySelector, G valueSelector) const
     {
         auto keys = select_i([keySelector](T value, int /*index*/)
         { 
             return keySelector(value); 
         }).toStdVector();

         auto values = select_i([valueSelector](T value, int /*index*/)
         { 
             return valueSelector(value); }
         ).toStdVector();
         
         std::map< _FRet, _GRet> toReturn;
          
         for (int i = 0; i < keys.size(); i++)
         {
             toReturn[keys[i]] = values[i];
         }

         return toReturn;
     }

One key difference (pun intended) is that this version does not throw an exception if they keys are not distinct, it just overwrites duplicate values in the loop. I do not need such a behavior for my purposes but it could be modified to mimic this as well.

Example usage:

        struct Tax {
	        std::string name;
	        int amount_1;
	        int amount_2;
        
	        bool operator ==(const Tax& tax) const {
		        return name == tax.name
			        && amount_1 == tax.amount_1
			        && amount_2 == tax.amount_2;
	        }
        };

	std::vector<Tax> taxes = {
	   {"tax 1", 1, 1},
	   {"tax 2", 1, 1},
	   {"tax 1", 2, 2},
	   {"tax 3", 3, 3},
	   {"tax 1", 4, 4},
	};
 
        auto resultMap = from(taxes)
        .groupBy([](const Tax& a) {return a.name; })
        .select([](const auto& pair) { // use of auto here needs c++14
          return Tax{
			          pair.first,
			          pair.second.sum([](const Tax& a) {return a.amount_1; }),
			          pair.second.sum([](const Tax& a) {return a.amount_2; })
          };
	}).toMap( [](const Tax& a) {return a.name; }, //key selector
	                [](const Tax& a) {return a.amount_1; });//value selector
        
        int value = resultMap["tax 1"];
        cout << value;

I don't know how to do this

I really like this implementation, but I don't know how to solve this:

struct Tax {
    std::string name;
    int amount_1;
    int amount_2;
    int amount_3;
};

std::vector<Tax> taxes = {
    {"tax 1", 1, 1},
    {"tax 2", 1, 1},
    {"tax 1", 2, 2},
    {"tax 3", 3, 3},
    {"tax 1", 4, 4},
};

The result that I expect would be a vector with these values, where for each tax.name the corresponding amounts are added

Dump result vector

"tax 1", 7, 7
"tax 2", 1, 1
"tax 3", 3, 3

Thanks in advance !

Investigate and introduce mutability and copy-ability of Ranges items

We need Ranges to allow modification items during enumeration. We need to investigate can this be achieved in the same syntax:

from(items).for_each([](Human & human){human.age += 1;})

or requires different constructors like:

mut_from(items).for_each([](Human & human){human.age += 1;})

The same question about unexpectedly producing copies - this should not happen actually. Or maybe we need a separate constructor for this:

int total = 0;
copy_from(items).for_each([](Human human){total += human.age;})

Plan:

  1. Checkout these issues: #22, #44
  2. I started experimenting with this here a while ago: #29
  3. Propose the best solution :)

Investigate and propose solution to make the library extremely useful. Prefer implicit over explicit mutability and copy-ability specification.

copy assgin

Hello! Every next call do a copy, how to pass a ref value?

Example:

struct test_t {
    std::string v1;
    int         v2;
};
constexpr std::size_t benchmarkVectorSize{ 1000000 };
std::vector<test_t> vecCpp(benchmarkVectorSize);

srand(0xDEADBEEF);

for (unsigned i = 0; i < benchmarkVectorSize; i++) {
    const auto x = rand();
    vecCpp[i].v2 = x;
    vecCpp[i].v1 = std::to_string(x);
}
boolinq::from(vecCpp).for_each([](test_t a) {
    a.v1;
    int iii = 02;
});

every for_each make object copy about 2 times
how to aviod this, and how can i change value in for_each ops;

I want this work well:

boolinq::from(vecCpp).for_each([](test_t &a) {
    a.v1 = "123"
});

Qt support

You say that there is "Qt collections", what exactly this means? Any examples?

Add AppVeyor CI config

We need AppVeyor build matrix to support at least 2 axis:

  1. Different C++ compilers (gcc, clang, msvc) with different major versions
  2. Different C++ standards: C++11, C++14, C++17, C++20 (boolinq-test14 is not compatible with C++11)

please extend your groupBy and select example

class Product{
public:
QString name;
QString no;
double quantity;
double price;
bool operator ==(const Product& pro) const {
return no.compare(pro.no) == 0;
}
};

Product pro1;
pro1.no = "1";
pro1.quantity= 1;
pro1.price= 10 ;
pro1.name= "1. Product";

Product pro2;
pro2.no = "2";
pro2.quantity= 2;
pro2.price= 20;
pro2.name= "2. Product";

Product pro3;
pro3.no = "1";
pro3.quantity= 1;
pro3.price= 10 ;
pro3.name= "1. Product";

QList list;
list.append(pro1);
list.append(pro2);
list.append(pro3);

auto dst = boolinq::from(list)
.groupBy([](const Product & a){return a.no;})
.select([](const auto & pair){
Product pro;
pro.no= pair.first;
pro.quantity= pair.second.sum([](const Product & a){return a.quantity;});
pro.price= pair.second.sum([](const Product & a){return a.price;});
pro.name = ???? // ****** here how to access name variable of Product class ********************
return pro;

       }).toStdList();

I know this is only a question not an issue. I have no any opportunity.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.