Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Котяра

Оценить эту запись

Структура данных FluentList

Запись от Котяра размещена 11.02.2010 в 11:29
Обновил(-а) Котяра 25.02.2010 в 09:50

Продолжаю эксперимены начатые в
Реализация Fluent interfaces
FDProject:fluentInterface_v2.zip

Класс FluentList
Код AS3:
package ru.k0t0vich.fluent 
{
	import flash.utils.getQualifiedClassName;
	import ru.k0t0vich.fluent.conditions.Condition;
	import ru.k0t0vich.fluent.parsers.FluentStringParser;
	import ru.k0t0vich.fluent.parsers.FluentXMLParser;
 
	/**
	 * Класс реализующий структуру данных: "Естественный список." (с)k0t0vich (smile:))
	 * Представляет собой список элементов с методами выборки и сортировки организованными на "естественном языке".
	 * Позволяет: выбирать элементы удовлетворяющиее условиям, производить групповые операции над элементами выборки,
	 * сортировать выборки по полям элементов, добавлять/удалять элементы из списка.
	 * 
	 * TODO: объединение/ разность списков.
	 * Выражение для выборки должны быть представлены в ДНФ(дизъюнктивно нормальная форма).
	 * @author k0t0vich
	 */
	public class FluentList
	{
		private var unitList:Array;
 
		private var dnfArray:Array = [];	
		private function get currConjunctionArray():Array { return dnfArray[dnfArray.length - 1] as Array; }
 
		public function FluentList($unitList:Array=null) 
		{
			if ($unitList) unitList = $unitList;
			else unitList = [];
			// начинаем дизъюнкцию
			clearConditions();
		}
 
 
		/**
		 * Синоним join()
		 * Добавить блок конъюнктов. 
		 * Дизъюнктивно объеденить с предыдущим блоком условий  (опрация ИЛИ)
		 * @return
		 */
		public function or():FluentList
		{
			dnfArray.push([]);
			return this;
		}
 
 
		/**
		 * Добавить в текущий конъюнкт условие (операция И)
		 * Валидность условия проверяется в рантайме.
		 * @param	$field  			поле элемента списка
		 * @param	$condition			условие (==,!=,<,>,<=,>=)	
		 * @param	$value				значение
		 * @return
		 */
		public function where($field:String, $condition:String, $value:*):FluentList
		{
			//trace("FluentList.where > $field : " + $field + ", $condition : " + $condition + ", $value : " + $value);
			currConjunctionArray.push(new Condition($field, $condition, $value));
			return this;
		}
 
		/**
		 * Синоним or() 
		 * Добавить блок конъюнктов. 
		 * Дизъюнктивно объеденить с предыдущим блоком условий  (опрация ИЛИ)
		 * @return
		 */
		public function join():FluentList
		{
			return or();
		}
 
		/**
		 *  Выбрать элементы удовлетворяюшие ДНФ
		 * @return
		 */		
		public function group():FluentList
		{
			var retFluentList:FluentList = new FluentList();
			var len:int = unitList.length;
			for (var i:int = 0; i < len; i++) 
			{
				var unit:* = unitList[i];
				if (valueConditionsWithUnit(unit))
				{
					retFluentList.push(unit);
				}
 
			}
			clearConditions();
			return retFluentList;
		}
 
		/**
		 * Очистить ДНФ
		 * @return
		 */
		private function clearConditions():FluentList
		{
			dnfArray = [];
			return or();
		}
 
		/**
		 * Разбираем ДНФ для юнита
		 * @param	unit
		 * @return
		 */
		private function valueConditionsWithUnit(unit:*):Boolean
		{
			var dnfLen:int = dnfArray.length;
			var dnfRet:Boolean = false;
			for (var i:int = 0; i < dnfLen; i++) 
			{
				var conjArray:Array = dnfArray[i] as Array;
				var conjLen:int = conjArray.length;
				var conjRet:Boolean = true;
 
				for (var j:int = 0; j < conjLen; j++) 
				{
					var condition:Condition =  conjArray[j] as Condition;
					if (!condition.valueCondition(unit))
					{
						conjRet = false;
						//досрочный выход из конъюнкта
						break;
					}
				}
				dnfRet = dnfRet || conjRet;
				if (dnfRet)	return true; // досрочный выход из дизъюнкта
			}
			return false;
		}
 
		/**
		 * Выполнить у юнитов удовлетворяющих ДНФ ф-цию
		 * @param	func : имя ф-ции
		 * @param	args : аргументы
		 */
		public function call(funcName:String,args:Array):FluentList
		{
			var len:int = unitList.length;
			for (var i:int = 0; i < len; i++) 
			{
				var unit:* = unitList[i];
				if (valueConditionsWithUnit(unit))
				{
					// действие над каждым отфильтрованным элементом
					try {
						var func:Function = unit[funcName];
					}
					catch (e:Error)
					{
						throw new Error("'"+funcName+"'"+ " is not member of "+ getQualifiedClassName(unit)+"! Standart error: "+e);
					}
					func.apply(unit, args);
				}
 
			}
			return clearConditions();
		}
 
		/**
		 * Выполнить ф-цию  над юнитами удовлетворяющими ДНФ
		 * @param	func : ф-ция вида func(unit:*,args)
		 * @param	args : аргументы
		 */
		public function execute(func:Function,...args):FluentList
		{
			var len:int = unitList.length;
			for (var i:int = 0; i < len; i++) 
			{
				var unit:* = unitList[i];
				if (valueConditionsWithUnit(unit))
				{
					func(unit, args);
				}
 
			}
			return clearConditions();
		}
 
 
		/**
		 * Распарсить XML сценария
		 * @param	xml
		 * @return
		 */
		public function parseXML(xml:XML):FluentList
		{
			return FluentXMLParser.parse(this,xml);
		}
 
		/**
		 * Распарсить Script сценария
		 * @param	xml
		 * @return
		 */
		public function parseString(str:String):FluentList
		{
			return FluentStringParser.parse(this,str);
		}
		/**
		 * Композиционные методы для массива
		 * TODO: добавить остальные
		 */
		public function push(unit:*):FluentList
		{
			unitList.push(unit);
			return this;
		}
 
 
		public function pop():*
		{
 
			return unitList.pop();
		}
 
		public function get length():int
		{
			return unitList.length;
		}
 
 
		public function toString():String
		{
			return "[FluentList" + String(unitList) + " ]";
 
		}
 
		public function sortOn(names:*,options:*=0):FluentList
		{
			unitList.sortOn(names, options);
			return group();
		}
	}
 
}
Тестовый класс:
Код AS3:
package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import ru.k0t0vich.fluent.conditions.Condition;
	import ru.k0t0vich.fluent.FluentList;
	import ru.k0t0vich.fluent.parsers.FluentStringParser;
	import ru.k0t0vich.units.Unit;
 
	/**
	 * Тестоый пример
	 * @author k0t0vich
	 */
	public class Main extends Sprite 
	{
 
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
 
			//Создаем список юнитов
			var enemies:FluentList = new FluentList();
 
			// Заполняем
			for (var i:int = 0; i < 10; i++) 
			{
				var unit:Unit = new Unit(i,-i*10);
				enemies.push(unit);
			}
 
 
 
 
			// весь список
			trace("TOTAL: " + enemies);
			// выполняем
			// 	Для всех юнитов с Z>-80 и Z<-50 
			//	c уровнем не меньше 5 или для юнитов с уровнем 1 
			//	отсортировать по Z и стрелять пушками типа 1 частотой 10.	
			trace("\r______тест AS3 выражения_________ ");
			var tmp1: FluentList = enemies
			.where(Unit.Z, Condition.GT, -80)
			.where(Unit.Z, Condition.LT, -50)
			.where(Unit.LEVEL, Condition.GE,5)
				.or()
			.where("level", "==", 1)
				.sortOn("z",Array.NUMERIC)
				.call(Unit.DO_SHOOT, [1, 10]);
			trace("tmp1 : " + tmp1);
 
			trace("\r______тест XML парсера_________ ");
			//тест парсера.
			var xml:XML = <data>
				<where field="z" condition="&gt;" value="-80" />
				<where field="z" condition="&lt;" value="-50" />
				<where field="level" condition="&gt;=" value="5" />
				<or/>
				<where field="level" condition="==" value="1" />
				<sort field="z" by="numeric"/>
				<call func="doShoot" args="1,10" />
				</data>
			var tmp2:FluentList = enemies.parseXML(xml);
			trace("tmp2 : " + tmp2);
 
			trace("\r______тест Script парсера_________ ");
			var str:String ='where z > -80;  where z < -50; where level >= 5; or; where("level", "==", 1); sortOn  z,numeric ; \r		 call           doShoot 1,10'; 
			var tmp3:FluentList = enemies.parseString(str);
			trace("tmp3 : " + tmp3);
			return;
 
		}
 
	}
 
}
В планах сделать несколько примеров по использованию:
- выборка товаров из магазина по нужным фильтрам
- z - сортировка в изо-мире
- загружаемый сценарий действий компьютерного оппонента в зависимости от уровня.
Размещено в ru.k0t0vich
Комментарии 8 Отправить другу ссылку на эту запись
Всего комментариев 8

Комментарии

Старый 11.05.2010 21:18 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Код AS3:
var tmp1: FluentList = enemies
			.where(Unit.Z, Condition.GT, -80)
			.where(Unit.Z, Condition.LT, -50)
			.where(Unit.LEVEL, Condition.GE,5)
				.or()
			.where("level", "==", 1)
				.sortOn("z",Array.NUMERIC)
				.call(Unit.DO_SHOOT, [1, 10]);
Это что такая за запись? Не встречал раньше...
Ааа, понял, голова тупит =) Выглядит непривычно.
Старый 27.05.2010 22:17 Nirth вне форума
Nirth
 
Аватар для Nirth
Это кстати отличная идея ))
И не менее отличная реализация ))
Старый 17.10.2010 03:24 mayakwd вне форума
mayakwd
 
Аватар для mayakwd
я так понимаю это в некотором роде mock?
для where было бы неплохо несколько условий одновременно например

Код AS3:
.where([new Condition("z", "eq", 100), new Condition("level", "gt", 15)]);
Старый 02.11.2010 00:45 Котяра вне форума
Котяра
 
Аватар для Котяра
2mayakwd
не совсем моки, скорее старый добрый sql для выборки данных
несколько условий, это то-же самое что or или and.
Код AS3:
.where([new Condition("z", "eq", 100), new Condition("level", "gt", 15)]);
аналог
Код AS3:
.where("z", "eq", 100)
.where ("level", "gt", 15)
в ДНФ можно представить любое выражение, как вам изместно)
само выражение вычисляется только при call, group итп.
Набор where только создают списки кондишинов. Да и парсеры выглядят проще.
Если говорить про парсеры строк, то вообще хороший декларатив получается..
Код AS3:
where z==100;
where level<15;
call jump 10;
или ты имеешь ввиду ?
Цитата:
where z==100 && level<15;
так мы к if (z==100 && level<15) Приедём)
Это всё конечно не OCAML.. так баловство. Мне именно идея с возвратом себя же или выборки своего же типа понравилась.
Обновил(-а) Котяра 02.11.2010 в 01:06
Старый 06.04.2011 04:44 BlooDHounD вне форума
BlooDHounD
 
Аватар для BlooDHounD
старый добрый sql старается комбинировать условия, а не выполнять их последовательно. тебе видимо в голову ударила тормознутость jquary =)
а ваще ты XMLList изобрёл =)
Старый 20.06.2011 17:33 Котяра вне форума
Котяра
 
Аватар для Котяра
Оказывается я "изобрел" LINQ)
Старый 20.06.2011 21:59 carrotoff вне форума
carrotoff
 
Аватар для carrotoff
Linq actionscript style!
Старый 21.06.2011 00:32 Котяра вне форума
Котяра
 
Аватар для Котяра
А вообще и правда - есть же мощный xml-e4x с фильтрами, сортировками, парсерами из/в строки..
Проще дописать monkey-patch для Array и XMLList или добавить какую статик утилиту переводящую из/в XMLList.
 

 


Часовой пояс GMT +4, время: 08:51.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.